Can you suggest me "How can I represent the hierarchical relationship through java class?"
you are welcomed to suggest other techniques.
For instance, User specifies that
"Room" belongs-to "Floor" and "Floor" belongs-to "Center"
I want to represent this relationship as Java class, and later want to retrieve this relationship.
-Pankesh
What you're talking about is standard object composition
'Belongs-to' and 'contains' are rather similar here. So for example:
public class Center
{
private List<Floor> floors;
...
public List<Floor> getFloors()
{
return this.floors;
}
}
public class Floor
{
private List<Room> rooms
...
}
public class Room
{
private String roomNumber;
...
}
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
An example of my problem is shown below. Both classes Car and Bike have the same fields (wheel and bodyColor).
In class AssembleVehicle, the method getDetails is almost duplicated for Car and Bike. Is there any way to remove redundancy or improve coding standards?
class Vehicle {
Car car;
Bike bike;
//setter & getter
}
class Car {
String wheel;
String bodyColor;
//setter & getter
}
class Bike {
String wheel;
String bodyColor;
//setter & getter
}
class AssembleVehicle {
public void init(Vehicle v) {
getDetails(v.getCar);
getDetails(v.getBike);
}
private void getDetails(Car c) {
String wheel = c.wheel;
String bodyColor = c.bodyColor;
}
private void getDetails(Bike c) {
String wheel = c.wheel;
String bodyColor = c.bodyColor;
}
}
Here, how we can remove code redundancy for getDetails?. Can we use this method only once?
What I understand about generics is: generics allow you to customize a "generic" method or class to whatever type you're working with. For example, suppose you have a method that adds two numbers together. In order to work with the types themselves, you might have to create multiple versions of this method.
Thinking about OOP in this way places the wrong emphasis. Even if you fix your initial mishap of having a Vehicle with a car and a bike inside of it, the 'improved' model of the Vehicle superclass with the wheel and bodyColor fields is probably broken (depending on the actual domain you are working in). For instance bike wheels and car wheels are very different, and a sleigh is a vehicle without any wheels. Things that look similar at first glance are not always good candidates to pull up into a super class.
The problem is that we are tempted to assume that if two examples of a category share some common traits, that these traits are present for all the members of this category (BTW this tendency to generalize might also be the cause of many problems in society).
The power of OOP does not come from extracting super classes like the Vehicle and 're-using' some fields. Direct subclassing is a very drastic measure that should not be applied lightly, because it means all present and future subclasses MUST inherit the complete contract (data and behavior) of the super class. As soon as you want to add a new subclass and are forced to make exceptions you know the model is wrong. And at that point changing it will impact all the existing sub classes. In fact, direct subclassing is nearly always a violation of the open-closed principle, the second in the set of SOLID design principles.
A much more flexible approach is to extract interfaces to encapsulate certain aspects of a category of classes:
interface Wheeled {
String getWheels();
}
class Car implements Wheeled {
private String wheels;
#Override
public String getWheels() {
return wheels;
}
}
class Bike implements Wheeled {
private String wheels;
#Override
public String getWheels() {
return wheels;
}
}
This would allow treating Cars and Bikes the same, if you are only interested in wheels:
List<Wheeled> wheeledVehicles = new ArrayList<>();
wheeledVehicles.add(new Car());
wheeledVehicles.add(new Bike());
String firstWheels = wheeledVehicles.get(0).getWheels());
If you are interested in body color, or even wheels AND body color, you are free to play with interfaces:
interface Wheeled {
String getWheels();
}
interface Coloured{
String getBodyColour();
}
interface WheeledAndColoured extends Wheeled, Coloured {}
Which allows:
List<WheeledAndColoured> wheeledAndColouredVehicles = new ArrayList<>();
wheeledAndColouredVehicles.add(new Car());
wheeledAndColouredVehicles.add(new Bike());
WheeledAndColoured first = wheeledAndColouredVehicles.get(0);
String firstWheels = first.getWheels());
String firstColour = first.getBodyColour());
If you really want to, you can extract the wheels field into a super class, but the immediate gain is limited. Private fields are an implementation detail, and pulling them into a super class is certainly not the type of re-use that will make a big difference. At the same time, it would create a very strong dependency between those classes and make future changes harder.
Maybe if you need to implement some 'complex' shared logic related to wheels, it is time to create the Wheels class:
class Wheels {
private String type;
private int number;
private BigDecimal price;
public BigDecimal getReplacementCosts() {
return price.multiply(BigDecimal.valueOf(number));
}
}
Now the Car class can collaborate with the Wheels class as one of its fields:
class Car implements Wheeled {
private Wheels wheels;
#Override
public String getWheels() {
return wheels.getType();
}
public BigDecimal getMaintenanceCosts() {
return wheels.getReplacementCosts();
}
}
Notice that, because we didn't tie in Car and Bike with a common super class, we are not forced to change either the Wheeled interface, nor the Bike class. If you want to add the Wheels logic to Bike then you can easily do so, but you are not forced to. You would be, if the wheels fields was in the shared super class Vehicle.
So the motto is: Favor collaboration over extension because it's way more flexible.
I agree with other commenters that the Vehicle class does not really make sense. I recommend following their advice and having Car and Bike extend the Vehicle class. This is better than using generics, because you can "guarantee" that you cannot use AssembleVehicle with classes that aren't vehicles and don't meet the requirements of having a wheel and a bodyColour.
However, if you still want to use generics, here is how you can use them:
class Car {
String wheel;
String bodyColor;
//setter & getter
}
class Bike {
String wheel;
String bodyColor;
//setter & getter
}
class AssembleVehicle <T> {
public void init(T vehicle) {
getDetails(vehicle);
}
private void getDetails(T vehicle) {
String wheel = vehicle.wheel;
String bodyColor = vehicle.bodyColor;
}
}
This allows you to write the getDetails method only once.
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.
Some background on the project: I am attempting to craft a space/sci-fi combat sim game with tabletop rpg style dice mechanics cranked up to 11 on the complexity scale, but still being transparent about the die rolls going on under the hood. I'm currently using the Star Wars Saga Edition combat rules as a basis.
Currently I'm trying to figure out a way to assign traits to vehicle.(possibly stored as a class for each vehicle) Each trait is an enum so that it can store multiple pieces of information. Here is the code I have for size categories:
public enum VehicleSize {
LARGE(1,"Speeder bike",5),HUGE(2,"Small Fighter",10),GARGANTUAN(5,"Tank, Medium Fighter",20),COLOSSAL(10,"Imperial Walker, Light Freighter",50),
COLLOSSALfrigate(10,"Corvette, Frigate",100),COLLOSSALcruiser(10,"Imperial-class Star Destroyer, Cruiser",200),
COLLOSSALstation(10,"The Death Star, Space Station",500);
private final int refMod;
private final int threshMod;
private final String desc;
VehicleSize(int reflexModifier,String example,int thresholdModifier)
{
refMod = reflexModifier;
desc = example;
threshMod = thresholdModifier;
}
public int getRefMod() {
return refMod;
}
public String getDesc() {
return desc;
}
public int getThreshMod() {
return threshMod;
}
}
My question is such: How do create vehicle profiles in such a way that I can assign this and similar enums as traits?
For practically all purposes, a field whose type is an enum class is no different than a field of any other object type, like Integer or String.
Create a private field, add a getter and setter, or if the field is final (likely in your case, because a vehicle instance can't change its type), add it as a constructor parameter and remo e the setter.
public class Vehicle {
private final VehicleSize vehicleSize;
// other fields
public Vehicle(VehicleSize vehicleSize) {
this.vehicleSize = vehicleSize;
}
public VehicleSize getVehicleSize() {
return vehicleSize;
}
// rest of class
}
There is nothing mysterious about an enum, other than the number of different instances of it are known at compile time (and a few more things, but nothing scary).
To add this into a class, you can use it like any user defined type.
public class MyClass {
private MyEnum myEnum;
}
I have member.objects that are painters, carpenters and TeamLeads which can have other TeamLeads, painters or carpenters under them. Is there a way to connect them so that I can getTeamLeads.team and also have the ability to see who is working under their TeamLeads.team. I understand how to do it with a database but wanted to see if composition or aggregation would handle a 1:m relationship and if there is an example somewhere that I could see. Would it require maybe a Team.class to link everyone or can it be handled by local references and I just can't find any examples.
As i see it you can do this with a private collection that can be managed by modifiers which also mantain reverse relationship something like this:
public class TeamMember {
private TeamMember leader;
private Set<TeamMember> teamMembers= new HashSet<TeamMember>();
public Set<TeamMember> getTeamMembers(){
return new HashSet<TeamMember>(teamMembers);
}
public void addTeamMember(TeamMember member){
if(member.leader!=null){
member.leader.removeTeamMember(member);
}
member.leader=this;
teamMembers.add(member);
}
public void removeTeamMember(TeamMember member){
member.leader=null;
teamMembers.remove(member);
}
public TeamMember getLeader(){
return leader;
}
}
Since you dont have public setters for teamMembers or leader the only way to change leader or teamMembers is by using the addTeamMember and removeTeamMember methods so you have the bidirectional relationship mantained by these methods.
I wish this may help.
So it sounds like you have some a method with this sort of signature to retrieve the list of TeamLead:
public List<TeamLead> getTeamLeads()
And from there, you want to get the members of each team, your TeamLead class would look something like this:
public class TeamLead {
private final List<Person> team = new ArrayList<Person> ();
// You can of course populate this list however is best for your code
public void addTeamMember(Person p) {
team.add(p);
}
public List<Person> getTeam() {
return team;
}
// more code...
}
Where Person is the base class for Painter, Carpenter, and TeamLead - there are other ways to do this without a class hierarchy, but I'll stick to this for easier explanation for now.
Currently, we have an business entity can be represented both as an enum or as a class.
The class implementation is easier and make business logic more clear. But there is probability of 50% that the requirements will change and an enum representation will make our life easier.
Concrete example
An entity has title and color. Color is editable, so there 2 ways
entity is an enum - there is another class with mapping from entity to its color.
entity is a class - just one more fiels for color, no problems.
Future change requirement - there should be rules associated with each entity
entity is an enum - the rules are hard coded in the code
entity is a class - there are needed few more classes for mapping and also an UI that will allow user to specify them.
In case the set of rules is static, the second option is an overkill.
So, in case we will need to transform the class to enum, are there any recommendations about this process ?
EDIT
The set of entities is limited and unlikely to be changed by user.
Thank you in advance.
If it has anything editable, you will need an entity class at some point anyway so go for the entity class first.
In case you have later a requirement for implementing a fixed set of rules, implement them as an enum with the hard coded rules, and add a field on your entity class that maps to that enum.
You can map enum on entity fields like this:
enum MyRule {
RULE1, RULE2;
// implement hard-coded rule
}
#Entity
class Myentity {
#Enumerated(/* optionally specify EnumType, default is ordinal */)
#Column
MyRule rule;
}
In case you want some functionality from enums and some from classes, then you could use mix of these:
public class ColoredTitle
{
private String color;
private Title title;
public ColoredTitle(String color, Title title)
{
this.color = color;
this.title = title;
}
public String getColor()
{
return color;
}
public void setColor(String color)
{
this.color = color;
}
public String getHeading()
{
return title.heading;
}
enum Title
{
FRONT_PAGE("Front Page"),
FOOTER_TITLE("Footer Title");
private String heading;
Title(String title)
{
this.heading = title;
}
}
}
Assuming that Entity means JPA entities.
You can use enum to return out to out side world and inside entity you can have property that represents it.
#Entity
class Entity {
#Column
Integer ruleIndex = 0;//Illustration purpose only
public Color getColor() {
// ruturn color based on rule that will be applied by ruleindex
}
}
enum Color {
BLUE(0), BLACK(1), WHITE(2);
private int ruleIndex = 0;
private Color(int ruleIndex) {
this.ruleIndex = ruleIndex;
}
}
Update
It is not advisable to use enums as entities. Instead you can use Single inheritance strategy
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="DISC", discriminatorType=STRING,length=20)
public class Color
{......}
#Entity
#DiscriminatorValue("Blue")
public class Blue extends Color
{......}
#Entity
#DiscriminatorValue("Green")
public class Green extends Color
{......}
This will allow you to store all the data in the same table and will allow you to also identify data based on objects.
Enums can have methods just like ordinary classes.
public enum Tree {
FIR("Fir Tree"),
BIRCH("Birch Tree");
private String desc;
public Tree(String desc) { this.desc = desc; }
public String getDesc() { return desc; }
public String getRandom() { return "abc"; }
}