I'm aware of the conceptual differences between Aggregation and Composition. Can someone tell me the implementation difference in Java between them with examples?
Composition
final class Car {
private final Engine engine;
Car(EngineSpecs specs) {
engine = new Engine(specs);
}
void move() {
engine.work();
}
}
Aggregation
final class Car {
private Engine engine;
void setEngine(Engine engine) {
this.engine = engine;
}
void move() {
if (engine != null)
engine.work();
}
}
In the case of composition, the Engine is completely encapsulated by the Car. There is no way for the outside world to get a reference to the Engine. The Engine lives and dies with the car. With aggregation, the Car also performs its functions through an Engine, but the Engine is not always an internal part of the Car. Engines may be swapped, or even completely removed. Not only that, but the outside world can still have a reference to the Engine, and tinker with it regardless of whether it's in the Car.
I would use a nice UML example.
Take a university that has 1 to 20 different departments and each department has 1 to 5 professors.
There is a composition link between a University and its' departments.
There is an aggregation link between a department and its' professors.
Composition is just a STRONG aggregation, if the university is destroyed then the departments should also be destroyed. But we shouldn't kill the professors even if their respective departments disappear.
In java :
public class University {
private List<Department> departments;
public void destroy(){
//it's composition, when I destroy a university I also destroy the departments. they cant live outside my university instance
if(departments!=null)
for(Department d : departments) d.destroy();
departments.clean();
departments = null;
}
}
public class Department {
private List<Professor> professors;
private University university;
Department(University univ){
this.university = univ;
//check here univ not null throw whatever depending on your needs
}
public void destroy(){
//It's aggregation here, we just tell the professor they are fired but they can still keep living
for(Professor p:professors)
p.fire(this);
professors.clean();
professors = null;
}
}
public class Professor {
private String name;
private List<Department> attachedDepartments;
public void destroy(){
}
public void fire(Department d){
attachedDepartments.remove(d);
}
}
Something around this.
EDIT: an example as requested
public class Test
{
public static void main(String[] args)
{
University university = new University();
//the department only exists in the university
Department dep = university.createDepartment();
// the professor exists outside the university
Professor prof = new Professor("Raoul");
System.out.println(university.toString());
System.out.println(prof.toString());
dep.assign(prof);
System.out.println(university.toString());
System.out.println(prof.toString());
dep.destroy();
System.out.println(university.toString());
System.out.println(prof.toString());
}
}
University class
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class University {
private List<Department> departments = new ArrayList<>();
public Department createDepartment() {
final Department dep = new Department(this, "Math");
departments.add(dep);
return dep;
}
public void destroy() {
System.out.println("Destroying university");
//it's composition, when I destroy a university I also destroy the departments. they cant live outside my university instance
if (departments != null)
departments.forEach(Department::destroy);
departments = null;
}
#Override
public String toString() {
return "University{\n" +
"departments=\n" + departments.stream().map(Department::toString).collect(Collectors.joining("\n")) +
"\n}";
}
}
Department class
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class Department {
private final String name;
private List<Professor> professors = new ArrayList<>();
private final University university;
public Department(University univ, String name) {
this.university = univ;
this.name = name;
//check here univ not null throw whatever depending on your needs
}
public void assign(Professor p) {
//maybe use a Set here
System.out.println("Department hiring " + p.getName());
professors.add(p);
p.join(this);
}
public void fire(Professor p) {
//maybe use a Set here
System.out.println("Department firing " + p.getName());
professors.remove(p);
p.quit(this);
}
public void destroy() {
//It's aggregation here, we just tell the professor they are fired but they can still keep living
System.out.println("Destroying department");
professors.forEach(professor -> professor.quit(this));
professors = null;
}
#Override
public String toString() {
return professors == null
? "Department " + name + " doesn't exists anymore"
: "Department " + name + "{\n" +
"professors=" + professors.stream().map(Professor::toString).collect(Collectors.joining("\n")) +
"\n}";
}
}
Professor class
import java.util.ArrayList;
import java.util.List;
public class Professor {
private final String name;
private final List<Department> attachedDepartments = new ArrayList<>();
public Professor(String name) {
this.name = name;
}
public void destroy() {
}
public void join(Department d) {
attachedDepartments.add(d);
}
public void quit(Department d) {
attachedDepartments.remove(d);
}
public String getName() {
return name;
}
#Override
public String toString() {
return "Professor " + name + " working for " + attachedDepartments.size() + " department(s)\n";
}
}
The implementation is debatable as it depends on how you need to handle creation, hiring deletion etc. Unrelevant for the OP
A simple Composition program
public class Person {
private double salary;
private String name;
private Birthday bday;
public Person(int y,int m,int d,String name){
bday=new Birthday(y, m, d);
this.name=name;
}
public double getSalary() {
return salary;
}
public String getName() {
return name;
}
public Birthday getBday() {
return bday;
}
///////////////////////////////inner class///////////////////////
private class Birthday{
int year,month,day;
public Birthday(int y,int m,int d){
year=y;
month=m;
day=d;
}
public String toString(){
return String.format("%s-%s-%s", year,month,day);
}
}
//////////////////////////////////////////////////////////////////
}
public class CompositionTst {
public static void main(String[] args) {
// TODO code application logic here
Person person=new Person(2001, 11, 29, "Thilina");
System.out.println("Name : "+person.getName());
System.out.println("Birthday : "+person.getBday());
//The below object cannot be created. A bithday cannot exixts without a Person
//Birthday bday=new Birthday(1988,11,10);
}
}
In simple terms :
Both Composition and Aggregation are Associations.
Composition -> Strong Has-A relationship
Aggregation -> Weak Has-A relationship.
There is a great explanation in the given url below.
http://www.codeproject.com/Articles/330447/Understanding-Association-Aggregation-and-Composit
Please check!!!
First we must talk about what actually the difference between Aggregation and Composition is to be on the same page.
Aggregation is an association where the associated entity may exist independent of the association. For example, a Person may be associated to an Organisation but he/she may have independent existence in the system.
whereas
Composition refers to a situation when one of the associated entities is strongly related to the other and cannot exist without the other's existence. In fact the identity of that entity is always associated with the identity of the other object. For example, wheels in a car.
Now, aggregation can simply be achieved by holding a property of one entity in another as below:
class Person {
Organisation worksFor;
}
class Organisation {
String name;
}
class Main {
public static void main(String args[]) {
//Create Person object independently
Person p = new Person();
//Create the Organisation independently
Organisation o = new Organisation();
o.name = "XYZ Corporation";
/*
At this point both person and organisation
exist without any association
*/
p.worksFor = o;
}
}
For Composition it is necessary that the dependent object is always created with the identity of its associated object. You can use an inner class for the same.
class Car {
class Wheel {
Car associatedWith;
}
}
class Main {
public static void main() {
//Create Car object independently
Car car = new Car();
//Cannot create Wheel instance independently
//need a reference of a Car for the same.
Car.Wheel wheel = car.new Wheel();
}
}
Please note that the same use case may fall under aggregation/composition depending on the application scenario. For example, the Person-Organisation case may become composition if you are developing an application for people working in some organisation and the reference to organisation is must for sign up. Similarly, if you are maintaining inventory for parts of a Car, Car-Wheel relationship can be aggregation.
The difference is that any composition is an aggregation and not vice versa.
Let's set the terms. The Aggregation is a metaterm in the UML standard, and means BOTH composition and shared aggregation, simply named shared. Too often it is named incorrectly "aggregation". It is BAD, for composition is an aggregation, too. As I understand, you mean "shared".
Further from UML standard:
composite - Indicates that the property is aggregated compositely,
i.e., the composite object has responsibility for the existence and
storage of the composed objects (parts).
So, University to cathedras association is a composition, because cathedra doesn't exist out of University (IMHO)
Precise semantics of shared aggregation varies by application area and
modeler.
I.e., all other associations can be drawn as shared aggregations, if you are only following to some principles of yours or of somebody else. Also look here.
Aggregation vs Composition
Aggregation implies a relationship where the child can exist independently of the parent. For example, Bank and Employee, delete the Bank and the Employee still exist.
whereas Composition implies a relationship where the child cannot exist independent of the parent. Example: Human and heart, heart don’t exist separate to a Human.
Aggregation relation is “has-a” and composition is “part-of” relation.
Composition is a strong Association whereas Aggregation is a weak Association.
Both types are of course associations, and not really mapped strictly to language elements like that. The difference is in the purpose, context, and how the system is modeled.
As a practical example, compare two different types of systems with similar entities:
A car registration system that primarily keep track of cars, and their owners, etc. Here we are not interested in the engine as a separate entity, but we may still have engine related attributes, like power, and type of fuel. Here the Engine may be a composite part of the car entity.
A car service shop management system that manages car parts, servicing cars, and replace parts, maybe complete engines. Here we may even have engines stocked and need to keep track of them and other parts separately and independent of the cars. Here the Engine may be an aggregated part of the car entity.
How you implement this in your language is of minor concern since at that level things like readability is much more important.
Related
I'm trying to get hold of the SOLID principles by Robert C. Martin. Currently I'm looking into low coupling & high cohesion. I've created some code which represents my current understanding of this subject. Could you guys tell me if on the right track? Any chance to improve the current design?
Main app which creates two addresses and assigns these to the employee:
public class App {
public static void main(String[] args) {
Address homeAddress = new HomeAddress("This is my Home Address");
Address workAddress = new WorkAddress("This is my Work Address");
Employee employee = new Employee(homeAddress, workAddress);
employee.getAddresses();
}
}
Employee class:
public class Employee {
private Address homeAddress;
private Address workAddress;
Employee(Address homeAddress, Address workAddress) {
this.homeAddress = homeAddress;
this.workAddress = workAddress;
}
public void getAddresses() {
System.out.println("homeAddress: " + homeAddress.getAddress());
System.out.println("workAddress: " + workAddress.getAddress());
}
}
Address interface:
public interface Address {
String getAddress();
}
Specific Address implementation 1(HomeAddress):
public class HomeAddress implements Address {
String specificAddress;
public HomeAddress(String specificAddress) {
this.specificAddress = specificAddress;
System.out.println("In HomeAddress Constructor");
}
public String getAddress() {
return specificAddress;
}
}
Specific Address implementation 2(WorkAddress):
public class WorkAddress implements Address {
String specificAddress;
public WorkAddress(String specificAddress) {
this.specificAddress = specificAddress;
System.out.println("In WorkAddress Constructor");
}
public String getAddress() {
return this.specificAddress;
}
}
Any help/feedback would be greatly appreciated! Thanks in advance.
Marc.
It's a smallish example, but it could be improved in terms of coupling/cohesion.
The objects are cohesive. Why? In the Employee object both the constructor and the getAddresses() (which should be called printAddresses() by the way) refer to both instance variables (which means they are concerned with the same thing). Same for the Address objects.
On the coupling part I think you could do better. As it stands now, the Employee objects "knows about" (i.e. is coupled to) the internal representation of the Address object. That is because you "export" the data (the String) from the Address object instead of printing it right there where the data is.
This makes your objects more coupled, and will cause any change (for example introducing Street and City and things like that) in the Address objects to leak up to the Employee. So it has real downsides.
The solution is to define a print() method in the Address and do the System.out.println() there. This is in line with other concepts, such as the Law of Demeter, Tell Don't Ask.
I was going through below link to figure out differentiation between Composition and Aggregation.
https://www.geeksforgeeks.org/association-composition-aggregation-java/
I am able to understand that Composition implies a relationship where the child cannot exist independent of the parent while Aggregation implies a relationship where the child can exist independently of the parent. But not able to understand how can i differentiate that programmatically . Below is an example of Aggregation and Composition as given in link.In both cases the classes are same in structure except that Student and Department class has an extra variable "name" .As in Composition "child cannot exist independent of the parent ",but here I can create a separate object of Book and use it without adding it to Library.
Aggregation
// student class
class Student
{
String name;
int id ;
String dept;
Student(String name, int id, String dept)
{
this.name = name;
this.id = id;
this.dept = dept;
}
}
/* Department class contains list of student
Objects. It is associated with student
class through its Object(s). */
class Department
{
String name;
private List<Student> students;
Department(String name, List<Student> students)
{
this.name = name;
this.students = students;
}
public List<Student> getStudents()
{
return students;
}
}
Composition
class Book
{
public String title;
public String author;
Book(String title, String author)
{
this.title = title;
this.author = author;
}
}
// Libary class contains
// list of books.
class Library
{
// reference to refer to list of books.
private final List<Book> books;
Library (List<Book> books)
{
this.books = books;
}
public List<Book> getTotalBooksInLibrary()
{
return books;
}
}
As far as I can tell (and maybe somebody else can give a better answer), you can't evaluate if the relationship is aggregation or composition just by looking at Java code. It's the other way around.
First you create a conceptual model of the world. Libraries have books, and cars have wheels. Then you think - does it make sense for a book to exist without a library, or for a wheel to exist without a car, in the context I'm working in. So for example if you are writing a car racing game, you will have no use of wheels outside of cars. But if you are writing some auto-repair application, you will deal with wheels independently of some particular car.
So first you decide if you need aggregation or composition, and then implement it in your code. The implementation could be that object Car has List<Wheel> but you can't tell if it's composition or aggregation just from that. The key is that you interpret the code (implementation) based on your conceptual model and then use it according to that.
If it's composition, the usage it might have some restrictions:
No object other than Car will hold a reference to Wheel.
Wheel might even be a private or package-private class.
If Car is saved in database, when you delete it, you also automatically delete all of its Wheels.
But it's up to you to enforce these restrictions if you decide it's composition.
In the real world, a book can indeed exist in its own right without being owned by a library. But what if, instead, you had a LibraryBook class with fields like dateAcquired and currentBorrower? Using your design, you would still be able to create a LibraryBook instance without a library.
This is where languages like C++ can be more explicit about composition: in C++, an object can hold its parts by value. In Java, every object is handled by a pointer (OK, Java people don't call them pointers; they call them references instead.) This makes it more difficult to differentiate between composition and aggregation. In Java, you do it using careful design.
For example, we can make the LibraryBook class only instantiable through a method of Library:
class Library {
class LibraryBook {
private LibraryBook() {/*private constructor prevents independent instantiation*/}
}
LibraryBook createBook(String title, etc...);
}
Furthermore, if we make LibraryBook's mutator methods only accessible to the Library class, we can ensure that the book remains part of its owning library.
public class ClassA_V01 {
private String name;
private int age;
// getter and setter
}
public class ClassA_V02 {
private String name;
private int age;
private int gender;
// getter and setter
}
public static void main(String[] args) {
SomeClass classA = new ClassA_V01();
classA.setName("myName);
classA.setAge(99);
performLogic(classA);
// OR
SomeClass classA = new ClassA_V02();
classA.setName("myName);
classA.setAge(99);
classA.setAge(1);
performLogic(classA);
}
public void performLogic(SomeClass classA) {
// do something
}
For strategy pattern to work, both classes must implement the same methods defined in the interface. But what if the classes need to have different fields and methods?
In my example, ClassA_V01 and ClassA_V02 are the same class except that one has more attribute "gender"
How does one implement the above such that classA can be equals to either ClassA_V01() or ClassA_V02?
"...For strategy pattern to work, both classes must implement the same methods defined in the interface. But what if the classes need to have different fields and methods?..." really this is not a criteria for strategy pattern.
Strategy pattern's intent is to identify and make family of algorithms interchangeable. If you read the pattern's documentation carefully, Strategy can be used when many related classes differ only in their behavior.
Appropriate decomposition is the key for better (extendable) design. A typical (but primitive) solution to Employee assignment, sub-classing tempEmp and permanentEmp types will put us in trouble and will not allow temp employee to become permanent in its life time (which has no meaning in real terms). This happens because we miss an important point- each employees employeeness is not different, they are all same type of employees with different pay policies. (same logic can be extended for Leave policy and so on)
This becomes simple if all types of employees have Salary computation based on same components (same state). But your question is what if TempEmployee gets only basicPay whereas PermanentEmployee gets basicPay as well as travelAllowance (additional attribute which is not present for TempEmp). This can be modeled by a combination of simple inheritance hierarchy along with strategy taking care of computation algorithm dependent upon Employee's (aka. Context) attribute (age)
public class Employee {
//name and id
private PayPackage payPackage;
private int age;
PayPackage strategy;
public double computeSalary() {
return payPackage.computePay(age);
}
//get/setPayPackage(...)
}
public abstract class PayPackage {
private double basicPay;
abstract public double computePay(int age);
protected double getBasicPay(){
return basicPay;
}
}
public class TempPayPackage extends PayPackage{
#Override
public double computePay(int age) {
double veteranAllowance = 0;
if (age > 40) {
veteranAllowance = 2000.00;
}
return getBasicPay() + veteranAllowance;
}
}
public class PermanentPayPackage extends PayPackage{
private double travelAllowance;
#Override
public double computePay(int age) {
double veteranAllowance = 0;
if (age > 40) {
veteranAllowance = 5000.00;
}
return getBasicPay() + travelAllowance + veteranAllowance;
}
}
Important thing to remember is Design patterns never work alone or as an alternative, they work hand in hand with Object oriented code and other patterns.
I've read and came to realize myself that entities (data objects - for JPA or serialization) with injections in them is a bad idea. Here is my current design (all appropriate fields have getters and setter, and serialVersionUID which I drop for brevity).
This is the parent object which is the head of the entity composition graph. This is the object I serialize.
public class State implements Serializable {
List<AbstractCar> cars = new ArrayList<>();
List<AbstractPlane> planes = new ArrayList<>();
// other objects similar to AbstractPlane as shown below
}
AbstractPlane and its subclasses are just simple classes without injections:
public abstract class AbstractPlane implements Serializable {
long serialNumber;
}
public class PropellorPlane extends AbstractPlane {
int propellors;
}
public class EnginePlane extends AbstractPlane {
List<Engine> engines = new ArrayList<>(); // Engine is another pojo
}
// etc.
In contrast, each concrete type of car requires a manager that holds some behavior and also some specific form of data:
public abstract class AbstractCar implements Serializable {
long serialNumber;
abstract CarData getData();
abstract void operate(int condition);
abstract class CarData {
String type;
int year;
}
}
public class Car1 extends AbstractCar {
#Inject
Car1Manager manager;
Car1Data data = new Car1Data(); // (getter exists per superclass requirement)
void operate(int i) { // logic looks weird but makes the example
if (i < 0)
return manager.operate(data);
else if (i > 1)
return manager.operate(data, i);
}
class Car1Data extends CarData {
int property1;
{
type = "car1";
year = 1;
}
}
}
public class Car2 extends AbstractCar {
#Inject
Car2Manager manager;
Car2Data data = new Car2Data();
void operate(int i) {
if (i < 31)
return manager.operate(data);
}
class Car2Data extends CarData {
char property2;
{
type = "car2";
year = 12;
}
}
}
// etc.
The CarxManager are #Stateless beans which perform operations on the data (the matching CarxData) given to them. They themselves further use injections of many other beans and they are all subclasses of AbstractCarManager. There are O(100) car types and matching managers.
The issue when serializing the State is that serializing the list of abstract cars does not play well with the injections in the subclasses. I'm looking for a design that decouples the injection from the data saving process.
My previous related questions: How to serialize an injected bean? and How can I tell the CDI container to "activate" a bean?
You can use the repository pattern. Place your business logic into a service and inject the repository (which abstracts the persistence mechanism) and manager into that. The repository hides the persistence implementation details from the business service and the entities are just simple POJOs.
It would look something like the below with Foo being the id of the entity Bar:
public class CarService {
#Inject
CarRepository carRepository;
#Inject
CarManager manager;
piblic void operate(final Foo foo) {
Bar myBar = carRepository.retrieve(foo);
manager.doSomethingTo(myBar);
carRepository.persist(myBar);
}
}
See also: Repository Pattern Step by Step Explanation, http://deviq.com/repository-pattern/. Some frameworks such as Spring Data JPA or deltaspike already implement the repository pattern for you, all you need to do is provide an interface like the following and they generate the implementation in the background:
#Repository
public interface CarRepository extends EntityRepository<Car, UUID> {}
Mark in answer to your request for more detail I am going to provide a remodeled solution because the example in the question really did not make sense to me and exhibits quite a few anti-patterns which lead to problematic software.
To find a good solution to the problem touches on a lot of different considerations, many of which are very large topics with many books written about them, but I will try my best to illustrate my thinking based on these to solve the above problem.
And apologies as I have no doubt you are aware of many of these, but I shall assume limited knowledge for the sake of clarity.
The first step in solving this problem is not about code, but about the model itself, model driven development is covered extensively in Eric Evan's book as mentioned in the comments below. The model should drive the implementation and should also exist on its own tier as part of a layered architecture and is made up of entities, value objects and factories.
Model Driven Development
In the model given in the question we have something called a State, which contains AbstractPlanes and AbstractCars. You are using JPA to persists the State which is effectively an aggregate of your planes and cars. Firstly calling anything a State in software is a bad smell because pretty much everything has some sort of state, but calling what we have here which is an aggregate the State makes even less sense.
How does one State differ from another? Is one car part of one State and another part of a different State or is it the case that all planes and cars belong to a single instance of State. What is the relationship between planes and cars in this scenario? How does a list of planes and a list of cars have any relation to a single State entity?
Well if State was actually an Airport and we were interested in how many planes and cars were currently on the ground, then this could be the correct model. If State was an Airport it would have a name or identity such as its airport code, but it does not and so...
... in this case, it seems that State is an object which is being used as a convenience to allow us to access the object model. So we are effectively driving our model by implementation considerations, when we should doing it the other way round and driving our implementation from our model.
Terms like CarData are also problematic for the same reason, creating a Car entity and then a separate object to store its Data is messy and confusing.
Failure to get the model right results in software that is at best confused and at worst completely non-functional. This is one of the largest causes of failed IT programmes and the bigger the project the harder this stuff is to get right.
Revised Model
So from the model I understand that we have Cars and we have Planes, instances of which are all unique entities with their own identity. They seem to me to be separate things and so there is no point in persisting them wrapped in some aggregate entity.
public class Plane {...}
public class Car {...}
Another consideration is the use of abstract classes in the model, generally we want to apply the principle of favoring composition over inheritance because inheritance can result in hidden behaviors and it can make a model hard to read. For example why have we got a ProperllerPlane and an EnginePlane? Surely a propeller is just a type of engine? I have greatly simplified the model:
public class Plane implements Serializable {
#Id
private String name;
private String model;
private List<Engine> engines;
The Plane is an entity with its own attributes and identity. There is no need to have additional classes which represent nothing in the real world just to store attributes. The engine object is currently an enum representing the type of engine used in the plane:
public enum Engine {
PROPELLER, JET
}
If the engine itself were to require an identity, as in real life engine serial numbers and things are tracked, then we would change this to an object. But we might not want to allow access to it except through a Plane entity instance, in which case the Plane will be known as a aggregate root - this is an advanced topic and I would recommend Evan's book for more details on aggregates.
The same goes for the Car entity.
#Entity
public class Car implements Serializable{
#Id
private String registration;
private String type;
private int year;
The above is all you need from what was provided in the question for the basis of your model. I have then created a couple of factory classes which handle creation of instances of these entities:
public class CarFactory {
public Car makePosrche(final String registrationNumber) {
Car porsche = new Car();
porsche.setRegistration(registrationNumber);
porsche.setType("Posrshe");
porsche.setYear(1986);
return porsche;
}
}
public class PlaneFactory {
public Plane makeSevenFourSeven(final String name) {
Plane sevenFourSeven = new Plane();
List<Engine> engines = new ArrayList<Engine>();
engines.add(JET);
engines.add(JET);
engines.add(JET);
engines.add(JET);
sevenFourSeven.setEngines(engines);
sevenFourSeven.setName(name);
return sevenFourSeven;
}
public Plane makeSpitFire(final String name) {
Plane spitFire = new Plane();
List<Engine> engines = new ArrayList<Engine>();
engines.add(PROPELLER);
spitFire.setEngines(engines);
spitFire.setModel("Spitfire");
spitFire.setName(name);
return spitFire;
}
}
What we are also doing here is separating out concerns as according to the Single Responsibility Principle each class should only really do one thing.
Now that we have a model we need to know how to interact with it. In this case we would most likely if using JPA persist the Cars in a table called Car and the Planes likewise. We would provide access to these persisted entities via repositories, CarRepository and PlaneRespository.
You can then create classes called services which inject the repositories (and anything else you require) to perform CRUD (Create Read Update Delete) operations on the instances of cars and planes and also this is the point where you can apply your business logic to these. Such as your method:
void operate(int i) {..}
By structuring your code this way you decouple the model (entities and value objects) from how they are persisted (repositories) from the services which operate on them as mentioned in your question:
I'm looking for a design that decouples the injection from the data saving process.
A possibility is to remove the property, so it won't be picked up by the serializers. This can be achieved be getting it programmatically.
private Car2Manager getCar2Manager() {
CDI.current().select(Car2Manager.class).get();
}
I would not consider this a clean solution, but it should be a workable "solution"
Also which might work is using JPA's #Transient:
#Inject
#Transient
Car2Manager manager;
I have not tested this, so it might not work.
What is the entry point?
Is this a web application, a rest service, a soap service, or event a scheduler?
Injection frameworks almost always separate data and service. Data are always POJO, containing absolutely no business logic. Here, assuming this is a rest-service, i will do the following:
public class SSOApplication {
public class State implements Serializable {
List<AbstractCar> cars = new ArrayList<>();
List<AbstractPlane> planes = new ArrayList<>();
// other objects similar to AbstractPlane as shown below
}
public abstract class AbstractPlane implements Serializable {
long serialNumber;
}
public class PropellorPlane extends AbstractPlane {
int propellors;
}
public class EnginePlane extends AbstractPlane {
List<Engine> engines = new ArrayList<>(); // Engine is another pojo
}
public abstract class AbstractCar implements Serializable {
long serialNumber;
abstract CarData getData();
}
public static class CarData {
String type;
int year;
}
public class Car2Data extends CarData {
char property2;
{
type = "car2";
year = 12;
}
}
public static class Car1Data extends CarData {
int property1;
{
type = "car1";
year = 1;
}
}
public static class Car1 extends AbstractCar {
#Override
CarData getData() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
public static class Car2 extends AbstractCar {
#Override
CarData getData() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
public static interface CarManager<T extends CarData> {
void operate(T car, int index);
default boolean canHandle(T carData) {
final TypeToken<T> token = new TypeToken<T>(getClass()) {
};
return token.getType() == carData.getClass();
}
}
#ApplicationScoped
public static class Car1Manager implements CarManager<Car1Data> {
public void operate(Car1Data car, int index) {
}
}
#ApplicationScoped
public static class Car2Manager implements CarManager<Car2Data> {
public void operate(Car2Data car, int index) {
}
}
#ApplicationScoped
public static class CarService {
#Any
#Inject
private Instance<CarManager<?>> carManagers;
public void operate(int index, AbstractCar car) {
final CarData carData = car.getData();
final CarManager<?> carManager = carManagers.stream()
.filter((mng) -> mng.canHandle(carData))
.findFirst()
.orElse(IllegalArgumentException::new);
carManager.operate(carData, index);
}
}
}
If you could alter your flow than perhaps you could do something like this:
class Car1InnerService {
#Inject
Car1Manager manager;
void operate(int i, Car1 car) {
if (i < 0)
return manager.operate(car.getData());
else if (i > 1)
return manager.operate(car.getData(), i);
}
}
}
I introduced some inner service which will operate on Car1 and use Car1Manager for it. Your AbstractCar class will also of course lose it's operate method because from now on your service will handle it. So now instead of calling car1.operate(i) you will have to make a call via Service like this:
public class SampleCar1ServiceUsage{
#Inject
Car1InnerService car1InnerService;
public void carManipulator(List<Car1> carlist){
int i = 0; //I don't know why you need this param therefore i just increment it
for(Car1 car: carlist){
car1InnerService.operate(i, car);
i++;
}
}
}
Of course you should introduce similar functionality for every other AbsractCar children (perhaps even extract some abstraction if necessary like for example AbsractCarInnerService which would define operate method or some interface which would do the same if you don't want any other solid methods in it). However this answer is still somehow related to #Justin Cooke answer and in my opinion you should definitely check those patterns which he mentioned in his post.
I have to build a library management system and i've run into problems while trying to implement user types or profiles. I've already got a superclass user and two other subclasses of User, Student and Teacher, each with their own "characteristics". The thing is i have to implement 7 types of users (5 types of students and 2 types of clerks) based on the number of books they can borrow and the amount of time they can keep the books until they have to return them. Those are the only 2 differences between the classes.
How would you implement this? Inheritance? I'm looking for a clever way to implement this and i would love to hear your thoughts on this.
Thank you very much.
As a good rule of thumb, anywhere you see a noun in a project specification it's a good candidate for a class. If those nouns have relationships in the project spec, they probably aught to have one in your code too.
All of your people would fit in the category of a Userso perhaps this should be an interface they would all inherit. Down from this they appear to fit into two categories, Student and Staff perhaps these should also be abstract classes / interfaces. Then you have your 7 concrete classes. 2 inheriting Staff and 5 inheriting Student.
So you'd end up with something like this..
Of course, this design depends on what every User must do, what every Staff / Student must do but I'll leave the very specific details to you.
You have a "class" per person, which really limits your design; because, if you want to add a student or teacher, you need to start writing a new class.
Classes are templates, and each template is used to construct an "instance of the class" or more specifically an "instance". One template is typically used to construct more than one class (although it is not necessary for a class to be used more than once, using it once (or not using it at all) is fine).
So you could do
public class Student {
private String name;
public Student(String name) {
this.name = name;
}
public string getName() {
return this.name;
}
}
public class Staff {
private String name;
public Staff(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
As you can see, there is going to be a lot of duplication between staff and students. getName(), getAge(), getPhoneNumber(), getAddress(), etc can easily be applied to both, which under this structure means that you would have to duplicate those methods for both Student and Staff.
What does both a staff member and a student have in common? They are both People, and many of the common methods are common to all people.
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
public Staff extends Person {
public void teachClass(Class class) {
...
}
}
public Student extends Person {
public void attendClass(Class class) {
...
}
}
This design also creates other issues, as it implies that a Staff member is not a Student, and a Student is not a Staff member. In the real world, sometimes the Staff enrolls for classes, and Students can take on teaching roles (think teacher's aide).
The most flexible method actually doesn't create a structural differentiation between a Student and Staff, it differentiates between the two by ability.
public class Person {
public Person(String name) {
...
}
public void canTeach(Course course) {
teaching.add(course);
}
public void attending(Course course) {
attending.add(course);
}
public boolean isStaff() {
return !teaching.isEmpty();
}
public boolean isStudent() {
return !attending.isEmpty();
}
}
However, this structure is radically different from the example you are being presented in class, and it side-steps the lessons you really are supposed to be learning about inheritance.