From 55d33379a34531218122c989c39bb82c2c07a8a0 Mon Sep 17 00:00:00 2001 From: HabibaMekay Date: Tue, 3 Dec 2024 19:40:58 +0200 Subject: [PATCH 1/7] sample classes and tests --- pom.xml | 1 + table-inheritance/pom.xml | 40 +++++++++++ .../src/main/java/com/iluwatar/Car.java | 22 ++++++ .../src/main/java/com/iluwatar/Main.java | 24 +++++++ .../src/main/java/com/iluwatar/Truck.java | 20 ++++++ .../src/main/java/com/iluwatar/Vehicle.java | 48 +++++++++++++ .../java/com/iluwatar/Vehicle_Database.java | 36 ++++++++++ .../src/test/java/VehicleDatabaseTest.java | 71 +++++++++++++++++++ 8 files changed, 262 insertions(+) create mode 100644 table-inheritance/pom.xml create mode 100644 table-inheritance/src/main/java/com/iluwatar/Car.java create mode 100644 table-inheritance/src/main/java/com/iluwatar/Main.java create mode 100644 table-inheritance/src/main/java/com/iluwatar/Truck.java create mode 100644 table-inheritance/src/main/java/com/iluwatar/Vehicle.java create mode 100644 table-inheritance/src/main/java/com/iluwatar/Vehicle_Database.java create mode 100644 table-inheritance/src/test/java/VehicleDatabaseTest.java diff --git a/pom.xml b/pom.xml index ef3a39265d53..987da947b896 100644 --- a/pom.xml +++ b/pom.xml @@ -218,6 +218,7 @@ function-composition microservices-distributed-tracing microservices-idempotent-consumer + table-inheritance diff --git a/table-inheritance/pom.xml b/table-inheritance/pom.xml new file mode 100644 index 000000000000..07a58dacadbc --- /dev/null +++ b/table-inheritance/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + + table-inheritance + + + 17 + 17 + UTF-8 + + + + + org.junit.jupiter + junit-jupiter-engine + 5.7.0 + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + + + + + \ No newline at end of file diff --git a/table-inheritance/src/main/java/com/iluwatar/Car.java b/table-inheritance/src/main/java/com/iluwatar/Car.java new file mode 100644 index 000000000000..2f419813afaa --- /dev/null +++ b/table-inheritance/src/main/java/com/iluwatar/Car.java @@ -0,0 +1,22 @@ +package com.iluwatar; + +public class Car extends Vehicle { + private int numDoors; + + public Car(int year, String make, String model, int numDoors, int id) { + super(year, make, model, id); + this.numDoors = numDoors; + } + + public void SetNumDoors(int doors){ + this.numDoors=doors; + } + public int GetNumDoors(){ + return numDoors; + } + + @Override public String toString() { + return "Car{" + "id=" + getId() + ", make='" + getMake() + '\'' + ", model='" + getModel() + '\'' + ", year=" + getYear() + ", numberOfDoors=" + GetNumDoors() + '}'; + } + +} diff --git a/table-inheritance/src/main/java/com/iluwatar/Main.java b/table-inheritance/src/main/java/com/iluwatar/Main.java new file mode 100644 index 000000000000..c0ac10e684b5 --- /dev/null +++ b/table-inheritance/src/main/java/com/iluwatar/Main.java @@ -0,0 +1,24 @@ +package com.iluwatar; + +public class Main { + public static void main(String[] args) { + Vehicle_Database database = new Vehicle_Database(); + + Car car = new Car(2020, "Toyota", "Corolla", 4, 1); + Truck truck = new Truck(2018, "Ford", "F-150", 60,2); + + database.saveVehicle(car); + database.saveVehicle(truck); + + database.printAllVehicles(); + + Vehicle vehicle = database.getVehicle(car.getId()); + System.out.println("Retrieved Vehicle: " + vehicle); + + Car retrievedCar = database.getCar(car.getId()); + System.out.println("Retrieved Car: " + retrievedCar); + + Truck retrievedTruck = database.getTruck(truck.getId()); + System.out.println("Retrieved Truck: " + retrievedTruck); + } +} \ No newline at end of file diff --git a/table-inheritance/src/main/java/com/iluwatar/Truck.java b/table-inheritance/src/main/java/com/iluwatar/Truck.java new file mode 100644 index 000000000000..ed339a1ad4d6 --- /dev/null +++ b/table-inheritance/src/main/java/com/iluwatar/Truck.java @@ -0,0 +1,20 @@ +package com.iluwatar; + +public class Truck extends Vehicle { + private double loadCapacity; + + public Truck(int year, String make, String model, double loadCapacity, int id) { + super(year,make, model, id); + this.loadCapacity=loadCapacity; + } + + public void SetLoadCapacity(double capacity){ + this.loadCapacity=capacity; + } + public double GetLoadCapacity(){ + return loadCapacity; + } + + @Override public String toString() { + return "Truck{" + "id=" + getId() + ", make='" + getMake() + '\'' + ", model='" + getModel() + '\'' + ", year=" + getYear() + ", payloadCapacity=" + GetLoadCapacity() + '}'; } +} \ No newline at end of file diff --git a/table-inheritance/src/main/java/com/iluwatar/Vehicle.java b/table-inheritance/src/main/java/com/iluwatar/Vehicle.java new file mode 100644 index 000000000000..dcd1ebb54eda --- /dev/null +++ b/table-inheritance/src/main/java/com/iluwatar/Vehicle.java @@ -0,0 +1,48 @@ +package com.iluwatar; + +public class Vehicle{ + + private String make, model; + private int year, id; + + + Vehicle(int year, String make, String model, int id){ + this.make=make; + this.model=model; + this.year=year; + this.id=id; + } + + public void setMake(String make){ + this.make=make; + } + public String getMake() { + return make; + } + + public void setModel(String model){ + this.model=model; + } + public String getModel(){ + return model; + } + + public void setYear(int year){ + this.year=year; + } + public int getYear(){ + return year; + } + + public int getId() { + return id; + } + public void setId(int id) { + this.id = id; + } + + + @Override public String toString() { + return "Vehicle{" + "id=" + id + ", make='" + make + '\'' + ", model='" + model + '\'' + ", year=" + year + '}'; + } +} \ No newline at end of file diff --git a/table-inheritance/src/main/java/com/iluwatar/Vehicle_Database.java b/table-inheritance/src/main/java/com/iluwatar/Vehicle_Database.java new file mode 100644 index 000000000000..882bba1d6e27 --- /dev/null +++ b/table-inheritance/src/main/java/com/iluwatar/Vehicle_Database.java @@ -0,0 +1,36 @@ +package com.iluwatar; + +import java.util.HashMap; +import java.util.Map; + +public class Vehicle_Database { + private Map vehicleTable = new HashMap<>(); + private Map carTable = new HashMap<>(); + private Map truckTable = new HashMap<>(); + + public void saveVehicle(Vehicle vehicle){ + vehicleTable.put(vehicle.getId(), vehicle); + if(vehicle instanceof Car) + carTable.put(vehicle.getId(), (Car)vehicle); + else if (vehicle instanceof Truck) + truckTable.put(vehicle.getId(), (Truck)vehicle); + } + + public Vehicle getVehicle(int ID) { + return vehicleTable.get(ID); + } + + public Car getCar(int id) { + return carTable.get(id); + } + + public Truck getTruck(int id) { + return truckTable.get(id); + } + + public void printAllVehicles() { + for (Vehicle vehicle : vehicleTable.values()) { + System.out.println(vehicle); + } + } +} diff --git a/table-inheritance/src/test/java/VehicleDatabaseTest.java b/table-inheritance/src/test/java/VehicleDatabaseTest.java new file mode 100644 index 000000000000..caf6b7f12d5d --- /dev/null +++ b/table-inheritance/src/test/java/VehicleDatabaseTest.java @@ -0,0 +1,71 @@ +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.iluwatar.Vehicle_Database; +import com.iluwatar.Truck; +import com.iluwatar.Car; +import com.iluwatar.Vehicle; + + +public class VehicleDatabaseTest { + + private Vehicle_Database vehicleDatabase; + + @BeforeEach + public void setUp() { + vehicleDatabase = new Vehicle_Database(); + } + + @Test + public void testSaveAndRetrieveCar() { + Car car = new Car(2020, "Toyota", "Corolla", 4, 1); + vehicleDatabase.saveVehicle(car); + + Vehicle retrievedVehicle = vehicleDatabase.getVehicle(car.getId()); + assertNotNull(retrievedVehicle); + assertEquals(car.getId(), retrievedVehicle.getId()); + assertEquals(car.getMake(), retrievedVehicle.getMake()); + assertEquals(car.getModel(), retrievedVehicle.getModel()); + assertEquals(car.getYear(), retrievedVehicle.getYear()); + + Car retrievedCar = vehicleDatabase.getCar(car.getId()); + assertNotNull(retrievedCar); + assertEquals(car.GetNumDoors(), retrievedCar.GetNumDoors()); + } + + @Test + public void testSaveAndRetrieveTruck() { + Truck truck = new Truck(2018, "Ford", "F-150", 60,2); + vehicleDatabase.saveVehicle(truck); + + Vehicle retrievedVehicle = vehicleDatabase.getVehicle(truck.getId()); + assertNotNull(retrievedVehicle); + assertEquals(truck.getId(), retrievedVehicle.getId()); + assertEquals(truck.getMake(), retrievedVehicle.getMake()); + assertEquals(truck.getModel(), retrievedVehicle.getModel()); + assertEquals(truck.getYear(), retrievedVehicle.getYear()); + + Truck retrievedTruck = vehicleDatabase.getTruck(truck.getId()); + assertNotNull(retrievedTruck); + assertEquals(truck.GetLoadCapacity(), retrievedTruck.GetLoadCapacity()); + } + + @Test + public void testPrintAllVehicles() { + Car car = new Car(2020, "Toyota", "Corolla", 4, 1); + Truck truck = new Truck(2018, "Ford", "F-150", 60,2); + vehicleDatabase.saveVehicle(car); + vehicleDatabase.saveVehicle(truck); + + vehicleDatabase.printAllVehicles(); + + Vehicle retrievedCar = vehicleDatabase.getVehicle(car.getId()); + Vehicle retrievedTruck = vehicleDatabase.getVehicle(truck.getId()); + + assertNotNull(retrievedCar); + assertNotNull(retrievedTruck); + } +} From 1c070dbd631e5befbaec23cf844c4958dd5eec33 Mon Sep 17 00:00:00 2001 From: HabibaMekay Date: Tue, 3 Dec 2024 20:00:02 +0200 Subject: [PATCH 2/7] sample classes and tests --- table-inheritance/README.md | 51 +++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 table-inheritance/README.md diff --git a/table-inheritance/README.md b/table-inheritance/README.md new file mode 100644 index 000000000000..058d8dcd03e6 --- /dev/null +++ b/table-inheritance/README.md @@ -0,0 +1,51 @@ +# Table Inheritance + +**Category:** Data Access Pattern, Structural Pattern + +**Tags:** Decoupling, Inheritance, Polymorphism, Object Mapping, Persistence, Data Transformation + +--- + +## Intent +The **Table Inheritance** pattern models a class hierarchy in a relational database. Each class in the hierarchy is mapped to its own table, and the tables are linked through foreign keys representing the inheritance structure. + +This pattern is particularly useful for organizing complex data models when different subclasses have distinct properties that need to be stored in separate tables. + +--- + +## Real-World Example +Imagine a vehicle management system with a `Vehicle` superclass and subclasses such as `Car` and `Truck`. +- The `Vehicle` table stores attributes common to all vehicles. +- The subclass tables (`Car` and `Truck`) store attributes specific to each subclass. + +--- + +## Database Schema + +### Vehicle Table +| Column | Description | +|--------|-------------------------------------| +| id | Primary key | +| make | The make of the vehicle | +| model | The model of the vehicle | +| year | The manufacturing year of the vehicle | + +### Car Table +| Column | Description | +|------------------|-------------------------------------| +| id | Foreign key referencing `Vehicle(id)` | +| numberOfDoors | Number of doors in the car | + +### Truck Table +| Column | Description | +|-------------------|-------------------------------------| +| id | Foreign key referencing `Vehicle(id)` | +| payloadCapacity | Payload capacity of the truck | + +--- + +## Benefits +- Decouples subclasses into their own tables for easier management and scalability. +- Allows for flexibility in subclass-specific attributes without altering the base table. + +--- From bb3899a6bc16e134e80fde4e65426b2d38bd376c Mon Sep 17 00:00:00 2001 From: HabibaMekay Date: Tue, 3 Dec 2024 20:01:09 +0200 Subject: [PATCH 3/7] read me addition --- table-inheritance/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/table-inheritance/README.md b/table-inheritance/README.md index 058d8dcd03e6..d41cdf54a013 100644 --- a/table-inheritance/README.md +++ b/table-inheritance/README.md @@ -48,4 +48,4 @@ Imagine a vehicle management system with a `Vehicle` superclass and subclasses s - Decouples subclasses into their own tables for easier management and scalability. - Allows for flexibility in subclass-specific attributes without altering the base table. ---- +--- \ No newline at end of file From 50be6600896a881401c3600a2a436c517b73c3ea Mon Sep 17 00:00:00 2001 From: HabibaMekay Date: Wed, 4 Dec 2024 19:48:18 +0200 Subject: [PATCH 4/7] fix violations --- .../src/main/java/com/iluwatar/Car.java | 42 ++++++- .../src/main/java/com/iluwatar/Main.java | 15 ++- .../src/main/java/com/iluwatar/Truck.java | 52 +++++++-- .../src/main/java/com/iluwatar/Vehicle.java | 110 ++++++++++++++---- .../java/com/iluwatar/VehicleDatabase.java | 68 +++++++++++ .../java/com/iluwatar/Vehicle_Database.java | 36 ------ .../src/test/java/VehicleDatabaseTest.java | 38 ++++-- 7 files changed, 274 insertions(+), 87 deletions(-) create mode 100644 table-inheritance/src/main/java/com/iluwatar/VehicleDatabase.java delete mode 100644 table-inheritance/src/main/java/com/iluwatar/Vehicle_Database.java diff --git a/table-inheritance/src/main/java/com/iluwatar/Car.java b/table-inheritance/src/main/java/com/iluwatar/Car.java index 2f419813afaa..08dbeffc8873 100644 --- a/table-inheritance/src/main/java/com/iluwatar/Car.java +++ b/table-inheritance/src/main/java/com/iluwatar/Car.java @@ -1,22 +1,52 @@ package com.iluwatar; +/** + * Represents a car with a specific number of doors. + */ public class Car extends Vehicle { private int numDoors; + /** + * Constructs a Car object. + * + * @param year the manufacturing year + * @param make the make of the car + * @param model the model of the car + * @param numDoors the number of doors + * @param id the unique identifier for the car + */ public Car(int year, String make, String model, int numDoors, int id) { super(year, make, model, id); this.numDoors = numDoors; } - public void SetNumDoors(int doors){ - this.numDoors=doors; + /** + * Sets the number of doors for the car. + * + * @param doors the number of doors + */ + public void setNumDoors(int doors) { + this.numDoors = doors; } - public int GetNumDoors(){ + + /** + * Gets the number of doors for the car. + * + * @return the number of doors + */ + public int getNumDoors() { return numDoors; } - @Override public String toString() { - return "Car{" + "id=" + getId() + ", make='" + getMake() + '\'' + ", model='" + getModel() + '\'' + ", year=" + getYear() + ", numberOfDoors=" + GetNumDoors() + '}'; + @Override + public String toString() { + return "Car{" + + "id=" + getId() + + ", make='" + getMake() + '\'' + + ", model='" + getModel() + '\'' + + ", year=" + getYear() + + ", numberOfDoors=" + getNumDoors() + + '}'; } - } + diff --git a/table-inheritance/src/main/java/com/iluwatar/Main.java b/table-inheritance/src/main/java/com/iluwatar/Main.java index c0ac10e684b5..11a41ef955f5 100644 --- a/table-inheritance/src/main/java/com/iluwatar/Main.java +++ b/table-inheritance/src/main/java/com/iluwatar/Main.java @@ -1,11 +1,20 @@ package com.iluwatar; +/** + * The main entry point of the application demonstrating the use of vehicles. + */ public class Main { + + /** + * The main method to demonstrate adding and retrieving vehicles from the database. + * + * @param args command-line arguments + */ public static void main(String[] args) { - Vehicle_Database database = new Vehicle_Database(); + VehicleDatabase database = new VehicleDatabase(); Car car = new Car(2020, "Toyota", "Corolla", 4, 1); - Truck truck = new Truck(2018, "Ford", "F-150", 60,2); + Truck truck = new Truck(2018, "Ford", "F-150", 60, 2); database.saveVehicle(car); database.saveVehicle(truck); @@ -21,4 +30,4 @@ public static void main(String[] args) { Truck retrievedTruck = database.getTruck(truck.getId()); System.out.println("Retrieved Truck: " + retrievedTruck); } -} \ No newline at end of file +} diff --git a/table-inheritance/src/main/java/com/iluwatar/Truck.java b/table-inheritance/src/main/java/com/iluwatar/Truck.java index ed339a1ad4d6..7b018e720062 100644 --- a/table-inheritance/src/main/java/com/iluwatar/Truck.java +++ b/table-inheritance/src/main/java/com/iluwatar/Truck.java @@ -1,20 +1,56 @@ package com.iluwatar; +/** + * Represents a truck, a type of vehicle with a specific load capacity. + */ public class Truck extends Vehicle { private double loadCapacity; + /** + * Constructs a Truck object with the given parameters. + * + * @param year the year of manufacture + * @param make the make of the truck + * @param model the model of the truck + * @param loadCapacity the load capacity of the truck + * @param id the unique ID of the truck + */ public Truck(int year, String make, String model, double loadCapacity, int id) { - super(year,make, model, id); - this.loadCapacity=loadCapacity; + super(year, make, model, id); + this.loadCapacity = loadCapacity; // Added spaces around '=' } - public void SetLoadCapacity(double capacity){ - this.loadCapacity=capacity; + /** + * Sets the load capacity of the truck. + * + * @param capacity the new load capacity + */ + public void setLoadCapacity(double capacity) { + this.loadCapacity = capacity; // Added spaces around '=' } - public double GetLoadCapacity(){ + + /** + * Retrieves the load capacity of the truck. + * + * @return the load capacity + */ + public double getLoadCapacity() { return loadCapacity; } - @Override public String toString() { - return "Truck{" + "id=" + getId() + ", make='" + getMake() + '\'' + ", model='" + getModel() + '\'' + ", year=" + getYear() + ", payloadCapacity=" + GetLoadCapacity() + '}'; } -} \ No newline at end of file + /** + * Returns a string representation of the truck. + * + * @return a string with the truck's details + */ + @Override + public String toString() { + return "Truck{" + + "id=" + getId() + + ", make='" + getMake() + '\'' + + ", model='" + getModel() + '\'' + + ", year=" + getYear() + + ", payloadCapacity=" + getLoadCapacity() + + '}'; + } +} diff --git a/table-inheritance/src/main/java/com/iluwatar/Vehicle.java b/table-inheritance/src/main/java/com/iluwatar/Vehicle.java index dcd1ebb54eda..2dd58f1de475 100644 --- a/table-inheritance/src/main/java/com/iluwatar/Vehicle.java +++ b/table-inheritance/src/main/java/com/iluwatar/Vehicle.java @@ -1,48 +1,114 @@ package com.iluwatar; -public class Vehicle{ +/** + * Represents a generic vehicle with basic attributes like make, model, year, and ID. + */ +public class Vehicle { - private String make, model; - private int year, id; + private String make; + private String model; + private int year; + private int id; - - Vehicle(int year, String make, String model, int id){ - this.make=make; - this.model=model; - this.year=year; - this.id=id; + /** + * Constructs a Vehicle object with the given parameters. + * + * @param year the year of manufacture + * @param make the make of the vehicle + * @param model the model of the vehicle + * @param id the unique ID of the vehicle + */ + public Vehicle(int year, String make, String model, int id) { + this.make = make; // Added spaces around '=' + this.model = model; + this.year = year; + this.id = id; } - public void setMake(String make){ - this.make=make; + /** + * Sets the make of the vehicle. + * + * @param make the make to set + */ + public void setMake(String make) { + this.make = make; // Added spaces around '=' } + + /** + * Gets the make of the vehicle. + * + * @return the make + */ public String getMake() { return make; } - public void setModel(String model){ - this.model=model; + /** + * Sets the model of the vehicle. + * + * @param model the model to set + */ + public void setModel(String model) { + this.model = model; // Added spaces around '=' } - public String getModel(){ + + /** + * Gets the model of the vehicle. + * + * @return the model + */ + public String getModel() { return model; } - public void setYear(int year){ - this.year=year; + /** + * Sets the year of manufacture for the vehicle. + * + * @param year the year to set + */ + public void setYear(int year) { + this.year = year; // Added spaces around '=' } - public int getYear(){ + + /** + * Gets the year of manufacture for the vehicle. + * + * @return the year + */ + public int getYear() { return year; } + /** + * Gets the unique ID of the vehicle. + * + * @return the ID + */ public int getId() { return id; } + + /** + * Sets the unique ID of the vehicle. + * + * @param id the ID to set + */ public void setId(int id) { - this.id = id; + this.id = id; // Added spaces around '=' } - - @Override public String toString() { - return "Vehicle{" + "id=" + id + ", make='" + make + '\'' + ", model='" + model + '\'' + ", year=" + year + '}'; + /** + * Returns a string representation of the vehicle. + * + * @return a string with the vehicle's details + */ + @Override + public String toString() { + return "Vehicle{" + + "id=" + id + + ", make='" + make + '\'' + + ", model='" + model + '\'' + + ", year=" + year + + '}'; } -} \ No newline at end of file +} diff --git a/table-inheritance/src/main/java/com/iluwatar/VehicleDatabase.java b/table-inheritance/src/main/java/com/iluwatar/VehicleDatabase.java new file mode 100644 index 000000000000..0ebbcaabd0cb --- /dev/null +++ b/table-inheritance/src/main/java/com/iluwatar/VehicleDatabase.java @@ -0,0 +1,68 @@ +package com.iluwatar; + +import java.util.HashMap; +import java.util.Map; + +/** + * Manages the storage and retrieval of Vehicle objects, including Cars and Trucks. + */ +public class VehicleDatabase { + + private Map vehicleTable = new HashMap<>(); + private Map carTable = new HashMap<>(); + private Map truckTable = new HashMap<>(); + + /** + * Saves a vehicle to the database. If the vehicle is a Car or Truck, it is added to the respective table. + * + * @param vehicle the vehicle to save + */ + public void saveVehicle(Vehicle vehicle) { + vehicleTable.put(vehicle.getId(), vehicle); + if (vehicle instanceof Car) { + carTable.put(vehicle.getId(), (Car) vehicle); + } else if (vehicle instanceof Truck) { + truckTable.put(vehicle.getId(), (Truck) vehicle); + } + } + + /** + * Retrieves a vehicle by its ID. + * + * @param id the ID of the vehicle + * @return the vehicle with the given ID, or null if not found + */ + public Vehicle getVehicle(int id) { + return vehicleTable.get(id); + } + + /** + * Retrieves a car by its ID. + * + * @param id the ID of the car + * @return the car with the given ID, or null if not found + */ + public Car getCar(int id) { + return carTable.get(id); + } + + /** + * Retrieves a truck by its ID. + * + * @param id the ID of the truck + * @return the truck with the given ID, or null if not found + */ + public Truck getTruck(int id) { + return truckTable.get(id); + } + + /** + * Prints all vehicles in the database. + */ + public void printAllVehicles() { + for (Vehicle vehicle : vehicleTable.values()) { + System.out.println(vehicle); + } + } +} + diff --git a/table-inheritance/src/main/java/com/iluwatar/Vehicle_Database.java b/table-inheritance/src/main/java/com/iluwatar/Vehicle_Database.java deleted file mode 100644 index 882bba1d6e27..000000000000 --- a/table-inheritance/src/main/java/com/iluwatar/Vehicle_Database.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.iluwatar; - -import java.util.HashMap; -import java.util.Map; - -public class Vehicle_Database { - private Map vehicleTable = new HashMap<>(); - private Map carTable = new HashMap<>(); - private Map truckTable = new HashMap<>(); - - public void saveVehicle(Vehicle vehicle){ - vehicleTable.put(vehicle.getId(), vehicle); - if(vehicle instanceof Car) - carTable.put(vehicle.getId(), (Car)vehicle); - else if (vehicle instanceof Truck) - truckTable.put(vehicle.getId(), (Truck)vehicle); - } - - public Vehicle getVehicle(int ID) { - return vehicleTable.get(ID); - } - - public Car getCar(int id) { - return carTable.get(id); - } - - public Truck getTruck(int id) { - return truckTable.get(id); - } - - public void printAllVehicles() { - for (Vehicle vehicle : vehicleTable.values()) { - System.out.println(vehicle); - } - } -} diff --git a/table-inheritance/src/test/java/VehicleDatabaseTest.java b/table-inheritance/src/test/java/VehicleDatabaseTest.java index caf6b7f12d5d..c879ec6e9146 100644 --- a/table-inheritance/src/test/java/VehicleDatabaseTest.java +++ b/table-inheritance/src/test/java/VehicleDatabaseTest.java @@ -1,24 +1,32 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import com.iluwatar.Vehicle_Database; -import com.iluwatar.Truck; import com.iluwatar.Car; +import com.iluwatar.Truck; import com.iluwatar.Vehicle; +import com.iluwatar.VehicleDatabase; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; - +/** + * Unit tests for the {@link VehicleDatabase} class. + * Tests saving, retrieving, and printing vehicles of different types. + */ public class VehicleDatabaseTest { - private Vehicle_Database vehicleDatabase; + private VehicleDatabase vehicleDatabase; + /** + * Sets up a new instance of {@link VehicleDatabase} before each test. + */ @BeforeEach public void setUp() { - vehicleDatabase = new Vehicle_Database(); + vehicleDatabase = new VehicleDatabase(); } + /** + * Tests saving a {@link Car} to the database and retrieving it. + */ @Test public void testSaveAndRetrieveCar() { Car car = new Car(2020, "Toyota", "Corolla", 4, 1); @@ -33,12 +41,15 @@ public void testSaveAndRetrieveCar() { Car retrievedCar = vehicleDatabase.getCar(car.getId()); assertNotNull(retrievedCar); - assertEquals(car.GetNumDoors(), retrievedCar.GetNumDoors()); + assertEquals(car.getNumDoors(), retrievedCar.getNumDoors()); } + /** + * Tests saving a {@link Truck} to the database and retrieving it. + */ @Test public void testSaveAndRetrieveTruck() { - Truck truck = new Truck(2018, "Ford", "F-150", 60,2); + Truck truck = new Truck(2018, "Ford", "F-150", 60, 2); vehicleDatabase.saveVehicle(truck); Vehicle retrievedVehicle = vehicleDatabase.getVehicle(truck.getId()); @@ -50,13 +61,16 @@ public void testSaveAndRetrieveTruck() { Truck retrievedTruck = vehicleDatabase.getTruck(truck.getId()); assertNotNull(retrievedTruck); - assertEquals(truck.GetLoadCapacity(), retrievedTruck.GetLoadCapacity()); + assertEquals(truck.getLoadCapacity(), retrievedTruck.getLoadCapacity()); } + /** + * Tests saving multiple vehicles to the database and printing them. + */ @Test public void testPrintAllVehicles() { Car car = new Car(2020, "Toyota", "Corolla", 4, 1); - Truck truck = new Truck(2018, "Ford", "F-150", 60,2); + Truck truck = new Truck(2018, "Ford", "F-150", 60, 2); vehicleDatabase.saveVehicle(car); vehicleDatabase.saveVehicle(truck); From 37d4744e4e1a6c5685a8035c290aa25d02a754a8 Mon Sep 17 00:00:00 2001 From: HabibaMekay Date: Wed, 4 Dec 2024 20:35:08 +0200 Subject: [PATCH 5/7] fix quality (coverage) --- .../{Main.java => table/inheritance/App.java} | 5 +- .../iluwatar/{ => table/inheritance}/Car.java | 9 +- .../{ => table/inheritance}/Truck.java | 13 ++- .../{ => table/inheritance}/Vehicle.java | 2 +- .../inheritance}/VehicleDatabase.java | 2 +- .../src/test/java/VehicleDatabaseTest.java | 100 ++++++++++++++++-- 6 files changed, 113 insertions(+), 18 deletions(-) rename table-inheritance/src/main/java/com/iluwatar/{Main.java => table/inheritance/App.java} (93%) rename table-inheritance/src/main/java/com/iluwatar/{ => table/inheritance}/Car.java (81%) rename table-inheritance/src/main/java/com/iluwatar/{ => table/inheritance}/Truck.java (79%) rename table-inheritance/src/main/java/com/iluwatar/{ => table/inheritance}/Vehicle.java (98%) rename table-inheritance/src/main/java/com/iluwatar/{ => table/inheritance}/VehicleDatabase.java (97%) diff --git a/table-inheritance/src/main/java/com/iluwatar/Main.java b/table-inheritance/src/main/java/com/iluwatar/table/inheritance/App.java similarity index 93% rename from table-inheritance/src/main/java/com/iluwatar/Main.java rename to table-inheritance/src/main/java/com/iluwatar/table/inheritance/App.java index 11a41ef955f5..77bd327b1622 100644 --- a/table-inheritance/src/main/java/com/iluwatar/Main.java +++ b/table-inheritance/src/main/java/com/iluwatar/table/inheritance/App.java @@ -1,10 +1,9 @@ -package com.iluwatar; +package com.iluwatar.table.inheritance; /** * The main entry point of the application demonstrating the use of vehicles. */ -public class Main { - +public class App { /** * The main method to demonstrate adding and retrieving vehicles from the database. * diff --git a/table-inheritance/src/main/java/com/iluwatar/Car.java b/table-inheritance/src/main/java/com/iluwatar/table/inheritance/Car.java similarity index 81% rename from table-inheritance/src/main/java/com/iluwatar/Car.java rename to table-inheritance/src/main/java/com/iluwatar/table/inheritance/Car.java index 08dbeffc8873..2ba549db4b68 100644 --- a/table-inheritance/src/main/java/com/iluwatar/Car.java +++ b/table-inheritance/src/main/java/com/iluwatar/table/inheritance/Car.java @@ -1,4 +1,4 @@ -package com.iluwatar; +package com.iluwatar.table.inheritance; /** * Represents a car with a specific number of doors. @@ -17,6 +17,9 @@ public class Car extends Vehicle { */ public Car(int year, String make, String model, int numDoors, int id) { super(year, make, model, id); + if (numDoors <= 0) { + throw new IllegalArgumentException("Number of doors must be positive."); + } this.numDoors = numDoors; } @@ -26,6 +29,9 @@ public Car(int year, String make, String model, int numDoors, int id) { * @param doors the number of doors */ public void setNumDoors(int doors) { + if (doors <= 0) { + throw new IllegalArgumentException("Number of doors must be positive."); + } this.numDoors = doors; } @@ -49,4 +55,3 @@ public String toString() { + '}'; } } - diff --git a/table-inheritance/src/main/java/com/iluwatar/Truck.java b/table-inheritance/src/main/java/com/iluwatar/table/inheritance/Truck.java similarity index 79% rename from table-inheritance/src/main/java/com/iluwatar/Truck.java rename to table-inheritance/src/main/java/com/iluwatar/table/inheritance/Truck.java index 7b018e720062..906d26538fed 100644 --- a/table-inheritance/src/main/java/com/iluwatar/Truck.java +++ b/table-inheritance/src/main/java/com/iluwatar/table/inheritance/Truck.java @@ -1,4 +1,4 @@ -package com.iluwatar; +package com.iluwatar.table.inheritance; /** * Represents a truck, a type of vehicle with a specific load capacity. @@ -17,7 +17,10 @@ public class Truck extends Vehicle { */ public Truck(int year, String make, String model, double loadCapacity, int id) { super(year, make, model, id); - this.loadCapacity = loadCapacity; // Added spaces around '=' + if (loadCapacity <= 0) { + throw new IllegalArgumentException("Load capacity must be positive."); + } + this.loadCapacity = loadCapacity; } /** @@ -26,7 +29,10 @@ public Truck(int year, String make, String model, double loadCapacity, int id) { * @param capacity the new load capacity */ public void setLoadCapacity(double capacity) { - this.loadCapacity = capacity; // Added spaces around '=' + if (capacity <= 0) { + throw new IllegalArgumentException("Load capacity must be positive."); + } + this.loadCapacity = capacity; } /** @@ -54,3 +60,4 @@ public String toString() { + '}'; } } + diff --git a/table-inheritance/src/main/java/com/iluwatar/Vehicle.java b/table-inheritance/src/main/java/com/iluwatar/table/inheritance/Vehicle.java similarity index 98% rename from table-inheritance/src/main/java/com/iluwatar/Vehicle.java rename to table-inheritance/src/main/java/com/iluwatar/table/inheritance/Vehicle.java index 2dd58f1de475..3f8117ca22ee 100644 --- a/table-inheritance/src/main/java/com/iluwatar/Vehicle.java +++ b/table-inheritance/src/main/java/com/iluwatar/table/inheritance/Vehicle.java @@ -1,4 +1,4 @@ -package com.iluwatar; +package com.iluwatar.table.inheritance; /** * Represents a generic vehicle with basic attributes like make, model, year, and ID. diff --git a/table-inheritance/src/main/java/com/iluwatar/VehicleDatabase.java b/table-inheritance/src/main/java/com/iluwatar/table/inheritance/VehicleDatabase.java similarity index 97% rename from table-inheritance/src/main/java/com/iluwatar/VehicleDatabase.java rename to table-inheritance/src/main/java/com/iluwatar/table/inheritance/VehicleDatabase.java index 0ebbcaabd0cb..7112d09e3394 100644 --- a/table-inheritance/src/main/java/com/iluwatar/VehicleDatabase.java +++ b/table-inheritance/src/main/java/com/iluwatar/table/inheritance/VehicleDatabase.java @@ -1,4 +1,4 @@ -package com.iluwatar; +package com.iluwatar.table.inheritance; import java.util.HashMap; import java.util.Map; diff --git a/table-inheritance/src/test/java/VehicleDatabaseTest.java b/table-inheritance/src/test/java/VehicleDatabaseTest.java index c879ec6e9146..33f7335372f5 100644 --- a/table-inheritance/src/test/java/VehicleDatabaseTest.java +++ b/table-inheritance/src/test/java/VehicleDatabaseTest.java @@ -1,10 +1,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; -import com.iluwatar.Car; -import com.iluwatar.Truck; -import com.iluwatar.Vehicle; -import com.iluwatar.VehicleDatabase; +import com.iluwatar.table.inheritance.Car; +import com.iluwatar.table.inheritance.Truck; +import com.iluwatar.table.inheritance.Vehicle; +import com.iluwatar.table.inheritance.VehicleDatabase; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -12,7 +13,7 @@ * Unit tests for the {@link VehicleDatabase} class. * Tests saving, retrieving, and printing vehicles of different types. */ -public class VehicleDatabaseTest { +class VehicleDatabaseTest { private VehicleDatabase vehicleDatabase; @@ -28,7 +29,7 @@ public void setUp() { * Tests saving a {@link Car} to the database and retrieving it. */ @Test - public void testSaveAndRetrieveCar() { + void testSaveAndRetrieveCar() { Car car = new Car(2020, "Toyota", "Corolla", 4, 1); vehicleDatabase.saveVehicle(car); @@ -48,7 +49,7 @@ public void testSaveAndRetrieveCar() { * Tests saving a {@link Truck} to the database and retrieving it. */ @Test - public void testSaveAndRetrieveTruck() { + void testSaveAndRetrieveTruck() { Truck truck = new Truck(2018, "Ford", "F-150", 60, 2); vehicleDatabase.saveVehicle(truck); @@ -68,7 +69,7 @@ public void testSaveAndRetrieveTruck() { * Tests saving multiple vehicles to the database and printing them. */ @Test - public void testPrintAllVehicles() { + void testPrintAllVehicles() { Car car = new Car(2020, "Toyota", "Corolla", 4, 1); Truck truck = new Truck(2018, "Ford", "F-150", 60, 2); vehicleDatabase.saveVehicle(car); @@ -82,4 +83,87 @@ public void testPrintAllVehicles() { assertNotNull(retrievedCar); assertNotNull(retrievedTruck); } + + /** + * Tests the constructor of {@link Car} with valid values. + */ + @Test + void testCarConstructor() { + Car car = new Car(2020, "Toyota", "Corolla", 4, 1); + assertEquals(2020, car.getYear()); + assertEquals("Toyota", car.getMake()); + assertEquals("Corolla", car.getModel()); + assertEquals(4, car.getNumDoors()); + assertEquals(1, car.getId()); // Assuming the ID is auto-generated in the constructor + } + + /** + * Tests the constructor of {@link Car} with invalid number of doors (negative value). + */ + @Test + void testCarConstructorWithInvalidNumDoors() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new Car(2020, "Toyota", "Corolla", -4, 1); + }); + assertEquals("Number of doors must be positive.", exception.getMessage()); + } + + /** + * Tests the constructor of {@link Car} with zero doors. + */ + @Test + void testCarConstructorWithZeroDoors() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new Car(2020, "Toyota", "Corolla", 0, 1); + }); + assertEquals("Number of doors must be positive.", exception.getMessage()); + } + + /** + * Tests the constructor of {@link Truck} with invalid load capacity (negative value). + */ + @Test + void testTruckConstructorWithInvalidLoadCapacity() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new Truck(2018, "Ford", "F-150", -60, 2); + }); + assertEquals("Load capacity must be positive.", exception.getMessage()); + } + + /** + * Tests the constructor of {@link Truck} with zero load capacity. + */ + @Test + void testTruckConstructorWithZeroLoadCapacity() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new Truck(2018, "Ford", "F-150", 0, 2); + }); + assertEquals("Load capacity must be positive.", exception.getMessage()); + } + + /** + * Tests setting invalid number of doors in {@link Car} using setter (negative value). + */ + @Test + void testSetInvalidNumDoors() { + Car car = new Car(2020, "Toyota", "Corolla", 4, 1); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + car.setNumDoors(-2); + }); + assertEquals("Number of doors must be positive.", exception.getMessage()); + } + + /** + * Tests setting invalid load capacity in {@link Truck} using setter (negative value). + */ + @Test + void testSetInvalidLoadCapacity() { + Truck truck = new Truck(2018, "Ford", "F-150", 60, 2); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + truck.setLoadCapacity(-10); + }); + assertEquals("Load capacity must be positive.", exception.getMessage()); + } } + + From 54cc8d0cd5f53d1eb5ac936dc467148f04f4eb3f Mon Sep 17 00:00:00 2001 From: HabibaMekay Date: Wed, 4 Dec 2024 21:08:09 +0200 Subject: [PATCH 6/7] fix quality (coverage) #2 --- table-inheritance/src/test/java/AppTest.java | 28 ++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 table-inheritance/src/test/java/AppTest.java diff --git a/table-inheritance/src/test/java/AppTest.java b/table-inheritance/src/test/java/AppTest.java new file mode 100644 index 000000000000..885d3429c50f --- /dev/null +++ b/table-inheritance/src/test/java/AppTest.java @@ -0,0 +1,28 @@ +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.iluwatar.table.inheritance.App; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import org.junit.jupiter.api.Test; + +class AppTest { + + /** + * Tests if the main method runs without throwing exceptions and prints expected output. + */ + @Test + void testAppMainMethod() { + + ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + System.setOut(new PrintStream(outContent)); + + + App.main(new String[]{}); + + String output = outContent.toString(); + + assertTrue(output.contains("Retrieved Vehicle:")); + assertTrue(output.contains("Retrieved Car:")); + assertTrue(output.contains("Retrieved Truck:")); + } +} From f635eb238678f0378a190bbd1bd0650d3d3b5eea Mon Sep 17 00:00:00 2001 From: HabibaMekay Date: Mon, 9 Dec 2024 22:40:20 +0200 Subject: [PATCH 7/7] resolved comments --- table-inheritance/README.md | 184 ++++++++++++++++-- table-inheritance/pom.xml | 21 +- .../com/iluwatar/table/inheritance/App.java | 45 ++++- .../com/iluwatar/table/inheritance/Car.java | 13 +- .../com/iluwatar/table/inheritance/Truck.java | 12 +- .../iluwatar/table/inheritance/Vehicle.java | 80 +------- .../table/inheritance/VehicleDatabase.java | 7 +- table-inheritance/src/test/java/AppTest.java | 32 ++- 8 files changed, 258 insertions(+), 136 deletions(-) diff --git a/table-inheritance/README.md b/table-inheritance/README.md index d41cdf54a013..3e3ad4f53bf9 100644 --- a/table-inheritance/README.md +++ b/table-inheritance/README.md @@ -1,26 +1,135 @@ -# Table Inheritance +--- +title: "Table Inheritance Pattern in Java: Modeling Hierarchical Data in Relational Databases" +shortTitle: Table Inheritance +description: "Explore the Table Inheritance pattern in Java with real-world examples, database schema, and tutorials. Learn how to model class hierarchies elegantly in relational databases." +category: Data Access Pattern, Structural Pattern +language: en +tag: +- Decoupling +- Inheritance +- Polymorphism +- Object Mapping +- Persistence +- Data Transformation +--- -**Category:** Data Access Pattern, Structural Pattern +## Also Known As +- Class Table Inheritance +--- -**Tags:** Decoupling, Inheritance, Polymorphism, Object Mapping, Persistence, Data Transformation +## Intent of Table Inheritance Pattern +The Table Inheritance pattern models a class hierarchy in a relational database by creating +separate tables for each class in the hierarchy. These tables share a common primary key, which in +subclass tables also serves as a foreign key referencing the primary key of the base class table. +This linkage maintains relationships and effectively represents the inheritance structure. This pattern +enables the organization of complex data models, particularly when subclasses have unique properties +that must be stored in distinct tables. --- -## Intent -The **Table Inheritance** pattern models a class hierarchy in a relational database. Each class in the hierarchy is mapped to its own table, and the tables are linked through foreign keys representing the inheritance structure. +## Detailed Explanation of Table Inheritance Pattern with Real-World Examples -This pattern is particularly useful for organizing complex data models when different subclasses have distinct properties that need to be stored in separate tables. +### Real-World Example +Consider a **Vehicle Management System** with a `Vehicle` superclass and subclasses like `Car` and `Truck`. ---- +- The **Vehicle Table** stores attributes common to all vehicles, such as `make`, `model`, and `year`. Its primary key (`id`) uniquely identifies each vehicle. +- The **Car Table** and **Truck Table** store attributes specific to their respective types, such as `numberOfDoors` for cars and `payloadCapacity` for trucks. +- The `id` column in the **Car Table** and **Truck Table** serves as both the primary key for those tables and a foreign key referencing the `id` in the **Vehicle Table**. -## Real-World Example -Imagine a vehicle management system with a `Vehicle` superclass and subclasses such as `Car` and `Truck`. -- The `Vehicle` table stores attributes common to all vehicles. -- The subclass tables (`Car` and `Truck`) store attributes specific to each subclass. +This setup ensures each subclass entry corresponds to a base class entry, maintaining the inheritance relationship while keeping subclass-specific data in their own tables. + +### In Plain Words +In table inheritance, each class in the hierarchy is represented by a separate table, which +allows for a clear distinction between shared attributes (stored in the base class table) and +specific attributes (stored in subclass tables). + +### Martin Fowler Says + +Relational databases don't support inheritance, which creates a mismatch when mapping objects. +To fix this, Table Inheritance uses a separate table for each class in the hierarchy while maintaining +relationships through foreign keys, making it easier to link the classes together in the database. + +For more detailed information, refer to Martin Fowler's article on [Class Table Inheritance](https://martinfowler.com/eaaCatalog/classTableInheritance.html). + + +## Programmatic Example of Table Inheritance Pattern in Java + + +The `Vehicle` class will be the superclass, and we will have `Car` and `Truck` as subclasses that extend +`Vehicle`. The `Vehicle` class will store common attributes, while `Car` and `Truck` will store +attributes specific to those subclasses. + +### Key Aspects of the Pattern: + +1. **Superclass (`Vehicle`)**: + The `Vehicle` class stores attributes shared by all vehicle types, such as: + - `make`: The manufacturer of the vehicle. + - `model`: The model of the vehicle. + - `year`: The year the vehicle was manufactured. + - `id`: A unique identifier for the vehicle. + + These attributes are stored in the **`Vehicle` table** in the database. + +2. **Subclass (`Car` and `Truck`)**: + Each subclass (`Car` and `Truck`) stores attributes specific to that vehicle type: + - `Car`: Has an additional attribute `numberOfDoors` representing the number of doors the car has. + - `Truck`: Has an additional attribute `payloadCapacity` representing the payload capacity of the truck. + + These subclass-specific attributes are stored in the **`Car` and `Truck` tables**. + +3. **Foreign Key Relationship**: + Each subclass (`Car` and `Truck`) contains the `id` field which acts as a **foreign key** that +references the primary key (`id`) of the superclass (`Vehicle`). This foreign key ensures the +relationship between the common attributes in the `Vehicle` table and the specific attributes in the +subclass tables (`Car` and `Truck`). + + +```java +/** + * Superclass + * Represents a generic vehicle with basic attributes like make, model, year, and ID. + */ +public class Vehicle { + private String make; + private String model; + private int year; + private int id; + + // Constructor, getters, and setters... +} + +/** + * Represents a car, which is a subclass of Vehicle. + */ +public class Car extends Vehicle { + private int numberOfDoors; + + // Constructor, getters, and setters... +} + +/** + * Represents a truck, which is a subclass of Vehicle. + */ +public class Truck extends Vehicle { + private int payloadCapacity; + + // Constructor, getters, and setters... +} +``` ---- -## Database Schema + +## Table Inheritance Pattern Class Diagram + + + + + + + + + +## Table Inheritance Pattern Database Schema ### Vehicle Table | Column | Description | @@ -44,8 +153,49 @@ Imagine a vehicle management system with a `Vehicle` superclass and subclasses s --- -## Benefits -- Decouples subclasses into their own tables for easier management and scalability. -- Allows for flexibility in subclass-specific attributes without altering the base table. +## When to Use the Table Inheritance Pattern in Java + +- When your application requires a clear mapping of an object-oriented class hierarchy to relational tables. +- When subclasses have unique attributes that do not fit into a single base table. +- When scalability and normalization of data are important considerations. +- When you need to separate concerns and organize data in a way that each subclass has its own +table but maintains relationships with the superclass. + +## Table Inheritance Pattern Java Tutorials + +- [Software Patterns Lexicon: Class Table Inheritance](https://softwarepatternslexicon.com/patterns-sql/4/4/2/) +- [Martin Fowler: Class Table Inheritance](http://thierryroussel.free.fr/java/books/martinfowler/www.martinfowler.com/isa/classTableInheritance.html) + +--- + +## Real-World Applications of Table Inheritance Pattern in Java + +- **Vehicle Management System**: Used to store different types of vehicles like Car and Truck in separate tables but maintain a relationship through a common superclass `Vehicle`. +- **E-Commerce Platforms**: Where different product types, such as Clothing, Electronics, and Furniture, are stored in separate tables with shared attributes in a superclass `Product`. + +## Benefits and Trade-offs of Table Inheritance Pattern + +### Benefits + +- **Clear Structure**: Each class has its own table, making the data model easier to maintain and understand. +- **Scalability**: Each subclass can be extended independently without affecting the other tables, making the system more scalable. +- **Data Normalization**: Helps avoid data redundancy and keeps the schema normalized. + +### Trade-offs + +- **Multiple Joins**: Retrieving data that spans multiple subclasses may require joining multiple tables, which could lead to performance issues. +- **Increased Complexity**: Managing relationships between tables and maintaining integrity can become more complex. +- **Potential for Sparse Tables**: Subclasses with fewer attributes may end up with tables that have many null fields. + +## Related Java Design Patterns + +- **Single Table Inheritance** – A strategy where a single table is used to store all classes in an +inheritance hierarchy. It stores all attributes of the class and its subclasses in one table. +- **Singleton Pattern** – Used when a class needs to have only one instance. + + +## References and Credits ---- \ No newline at end of file +- **Martin Fowler** - [*Patterns of Enterprise Application Architecture*](https://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420) +- **Java Persistence with Hibernate** - [Link to book](https://www.amazon.com/Java-Persistence-Hibernate-Christian-Bauer/dp/193239469X) +- **Object-Relational Mapping on Wikipedia** - [Link to article](https://en.wikipedia.org/wiki/Object-relational_mapping) diff --git a/table-inheritance/pom.xml b/table-inheritance/pom.xml index 07a58dacadbc..9a886307ffe7 100644 --- a/table-inheritance/pom.xml +++ b/table-inheritance/pom.xml @@ -11,12 +11,6 @@ table-inheritance - - 17 - 17 - UTF-8 - - org.junit.jupiter @@ -24,17 +18,14 @@ 5.7.0 test + + org.projectlombok + lombok + 1.18.24 + provided + - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.22.2 - - - \ No newline at end of file diff --git a/table-inheritance/src/main/java/com/iluwatar/table/inheritance/App.java b/table-inheritance/src/main/java/com/iluwatar/table/inheritance/App.java index 77bd327b1622..4f848fb83e61 100644 --- a/table-inheritance/src/main/java/com/iluwatar/table/inheritance/App.java +++ b/table-inheritance/src/main/java/com/iluwatar/table/inheritance/App.java @@ -1,15 +1,48 @@ package com.iluwatar.table.inheritance; +import java.util.logging.Logger; + /** * The main entry point of the application demonstrating the use of vehicles. + * + *

The Table Inheritance pattern models a class hierarchy in a relational database by creating + * separate tables for each class in the hierarchy. These tables share a common primary key, which in + * subclass tables also serves as a foreign key referencing the primary key of the base class table. + * This linkage maintains relationships and effectively represents the inheritance structure. This + * pattern enables the organization of complex data models, particularly when subclasses have unique + * properties that must be stored in distinct tables. */ + public class App { /** - * The main method to demonstrate adding and retrieving vehicles from the database. + * Manages the storage and retrieval of Vehicle objects, including Cars and Trucks. + * + *

This example demonstrates the **Table Inheritance** pattern, where each vehicle type + * (Car and Truck) is stored in its own separate table. The `VehicleDatabase` simulates + * a simple database that manages these entities, with each subclass (Car and Truck) + * being stored in its respective table. + * + *

The `VehicleDatabase` contains the following tables: + * - `vehicleTable`: Stores all vehicle objects, including both `Car` and `Truck` objects. + * - `carTable`: Stores only `Car` objects, with fields specific to cars. + * - `truckTable`: Stores only `Truck` objects, with fields specific to trucks. + * + *

The example demonstrates: + * 1. Saving instances of `Car` and `Truck` to their respective tables in the database. + * 2. Retrieving vehicles (both cars and trucks) from the appropriate table based on their ID. + * 3. Printing all vehicles stored in the database. + * 4. Showing how to retrieve specific types of vehicles (`Car` or `Truck`) by their IDs. + * + *

In the **Table Inheritance** pattern, each subclass has its own table, making it easier + * to manage specific attributes of each subclass. * * @param args command-line arguments */ + public static void main(String[] args) { + + final Logger logger = Logger.getLogger(App.class.getName()); + VehicleDatabase database = new VehicleDatabase(); Car car = new Car(2020, "Toyota", "Corolla", 4, 1); @@ -21,12 +54,12 @@ public static void main(String[] args) { database.printAllVehicles(); Vehicle vehicle = database.getVehicle(car.getId()); - System.out.println("Retrieved Vehicle: " + vehicle); - Car retrievedCar = database.getCar(car.getId()); - System.out.println("Retrieved Car: " + retrievedCar); - Truck retrievedTruck = database.getTruck(truck.getId()); - System.out.println("Retrieved Truck: " + retrievedTruck); + + logger.info(String.format("Retrieved Vehicle: %s", vehicle)); + logger.info(String.format("Retrieved Car: %s", retrievedCar)); + logger.info(String.format("Retrieved Truck: %s", retrievedTruck)); + } } diff --git a/table-inheritance/src/main/java/com/iluwatar/table/inheritance/Car.java b/table-inheritance/src/main/java/com/iluwatar/table/inheritance/Car.java index 2ba549db4b68..b7332bf2a6b0 100644 --- a/table-inheritance/src/main/java/com/iluwatar/table/inheritance/Car.java +++ b/table-inheritance/src/main/java/com/iluwatar/table/inheritance/Car.java @@ -1,8 +1,10 @@ package com.iluwatar.table.inheritance; - +import lombok.Getter; /** * Represents a car with a specific number of doors. */ + +@Getter public class Car extends Vehicle { private int numDoors; @@ -35,15 +37,6 @@ public void setNumDoors(int doors) { this.numDoors = doors; } - /** - * Gets the number of doors for the car. - * - * @return the number of doors - */ - public int getNumDoors() { - return numDoors; - } - @Override public String toString() { return "Car{" diff --git a/table-inheritance/src/main/java/com/iluwatar/table/inheritance/Truck.java b/table-inheritance/src/main/java/com/iluwatar/table/inheritance/Truck.java index 906d26538fed..5d093c688c9e 100644 --- a/table-inheritance/src/main/java/com/iluwatar/table/inheritance/Truck.java +++ b/table-inheritance/src/main/java/com/iluwatar/table/inheritance/Truck.java @@ -1,8 +1,11 @@ package com.iluwatar.table.inheritance; +import lombok.Getter; + /** * Represents a truck, a type of vehicle with a specific load capacity. */ +@Getter public class Truck extends Vehicle { private double loadCapacity; @@ -35,15 +38,6 @@ public void setLoadCapacity(double capacity) { this.loadCapacity = capacity; } - /** - * Retrieves the load capacity of the truck. - * - * @return the load capacity - */ - public double getLoadCapacity() { - return loadCapacity; - } - /** * Returns a string representation of the truck. * diff --git a/table-inheritance/src/main/java/com/iluwatar/table/inheritance/Vehicle.java b/table-inheritance/src/main/java/com/iluwatar/table/inheritance/Vehicle.java index 3f8117ca22ee..1333f6a166ee 100644 --- a/table-inheritance/src/main/java/com/iluwatar/table/inheritance/Vehicle.java +++ b/table-inheritance/src/main/java/com/iluwatar/table/inheritance/Vehicle.java @@ -1,8 +1,14 @@ package com.iluwatar.table.inheritance; +import lombok.Getter; +import lombok.Setter; + /** * Represents a generic vehicle with basic attributes like make, model, year, and ID. */ + +@Setter +@Getter public class Vehicle { private String make; @@ -19,84 +25,12 @@ public class Vehicle { * @param id the unique ID of the vehicle */ public Vehicle(int year, String make, String model, int id) { - this.make = make; // Added spaces around '=' + this.make = make; this.model = model; this.year = year; this.id = id; } - /** - * Sets the make of the vehicle. - * - * @param make the make to set - */ - public void setMake(String make) { - this.make = make; // Added spaces around '=' - } - - /** - * Gets the make of the vehicle. - * - * @return the make - */ - public String getMake() { - return make; - } - - /** - * Sets the model of the vehicle. - * - * @param model the model to set - */ - public void setModel(String model) { - this.model = model; // Added spaces around '=' - } - - /** - * Gets the model of the vehicle. - * - * @return the model - */ - public String getModel() { - return model; - } - - /** - * Sets the year of manufacture for the vehicle. - * - * @param year the year to set - */ - public void setYear(int year) { - this.year = year; // Added spaces around '=' - } - - /** - * Gets the year of manufacture for the vehicle. - * - * @return the year - */ - public int getYear() { - return year; - } - - /** - * Gets the unique ID of the vehicle. - * - * @return the ID - */ - public int getId() { - return id; - } - - /** - * Sets the unique ID of the vehicle. - * - * @param id the ID to set - */ - public void setId(int id) { - this.id = id; // Added spaces around '=' - } - /** * Returns a string representation of the vehicle. * diff --git a/table-inheritance/src/main/java/com/iluwatar/table/inheritance/VehicleDatabase.java b/table-inheritance/src/main/java/com/iluwatar/table/inheritance/VehicleDatabase.java index 7112d09e3394..403112c32aa8 100644 --- a/table-inheritance/src/main/java/com/iluwatar/table/inheritance/VehicleDatabase.java +++ b/table-inheritance/src/main/java/com/iluwatar/table/inheritance/VehicleDatabase.java @@ -1,13 +1,18 @@ package com.iluwatar.table.inheritance; + import java.util.HashMap; import java.util.Map; +import java.util.logging.Logger; + /** * Manages the storage and retrieval of Vehicle objects, including Cars and Trucks. */ public class VehicleDatabase { + final Logger logger = Logger.getLogger(VehicleDatabase.class.getName()); + private Map vehicleTable = new HashMap<>(); private Map carTable = new HashMap<>(); private Map truckTable = new HashMap<>(); @@ -61,7 +66,7 @@ public Truck getTruck(int id) { */ public void printAllVehicles() { for (Vehicle vehicle : vehicleTable.values()) { - System.out.println(vehicle); + logger.info(vehicle.toString()); } } } diff --git a/table-inheritance/src/test/java/AppTest.java b/table-inheritance/src/test/java/AppTest.java index 885d3429c50f..9d4e74ebdd5b 100644 --- a/table-inheritance/src/test/java/AppTest.java +++ b/table-inheritance/src/test/java/AppTest.java @@ -3,26 +3,48 @@ import com.iluwatar.table.inheritance.App; import java.io.ByteArrayOutputStream; import java.io.PrintStream; +import java.util.logging.ConsoleHandler; +import java.util.logging.Handler; +import java.util.logging.Logger; import org.junit.jupiter.api.Test; +/** + * Tests if the main method runs without throwing exceptions and prints expected output. + */ + class AppTest { - /** - * Tests if the main method runs without throwing exceptions and prints expected output. - */ @Test - void testAppMainMethod() { + void testAppMainMethod() { ByteArrayOutputStream outContent = new ByteArrayOutputStream(); - System.setOut(new PrintStream(outContent)); + PrintStream printStream = new PrintStream(outContent); + + System.setOut(printStream); + Logger logger = Logger.getLogger(App.class.getName()); + + Handler handler = new ConsoleHandler() { + @Override + public void publish(java.util.logging.LogRecord recordObj) { + printStream.println(getFormatter().format(recordObj)); + } + }; + handler.setLevel(java.util.logging.Level.ALL); + logger.addHandler(handler); App.main(new String[]{}); String output = outContent.toString(); assertTrue(output.contains("Retrieved Vehicle:")); + assertTrue(output.contains("Toyota")); // Car make + assertTrue(output.contains("Ford")); // Truck make assertTrue(output.contains("Retrieved Car:")); assertTrue(output.contains("Retrieved Truck:")); } } + + + +