Avoid using instanceof with entities - java

Today I read this article about avoiding the use of instanceof.
This makes absolutely sense to me. I'm also aware of the visitor pattern.
Lets say I have the following situation:
#Entity
public abstract class Employee {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer employeeId;
private String name;
}
#Entity
public class FullTimeEmployee extends Employee {
protected Integer salary;
public Integer getSalary() {
return salary;
}
public void setSalary(Integer salary) {
this.salary = salary;
}
}
#Entity
public class PartTimeEmployee extends Employee{
protected Float hourlyWage;
public Float getHourlyWage() {
return hourlyWage;
}
public void setHourlyWage(Float hourlyWage) {
this.hourlyWage = hourlyWage;
}
}
How could I avoid using instanceof when calling a method like this?
public void convertEmployee(Employee employee) {
if (employee instanceof FullTimeEmployee) {
FullTimeEmployee fullTimeEmployee = (FullTimeEmployee) employee;
calcSalaray(fullTimeEmployee);
} else if (employee instanceof PartTimeEmployee) {
PartTimeEmployee partTimeEmployee = (PartTimeEmployee) employee;
calcHourlywage(partTimeEmployee);
}
}

Here is a simple example using the visitor pattern. The fact that your classes are entities is irrelevant. What matters is that the base class has a fixed, well-known number of subclasses.
Let's start with the abstract class:
public abstract class Employee {
public abstract void accept(EmployeeVisitor visitor);
}
It contains an accept() method taking a visitor as argument. Every subclass must override this method.
Now the two subclasses, each having a distinct set of fields and methods:
public class FrenchEmployee extends Employee {
private int eiffelTowerVisits;
#Override
public void accept(EmployeeVisitor visitor) {
visitor.visit(this);
}
public int getEiffelTowerVisits() {
return eiffelTowerVisits;
}
}
public class EnglishEmployee extends Employee {
private int towerBridgeVisits;
#Override
public void accept(EmployeeVisitor visitor) {
visitor.visit(this);
}
public int getTowerBridgeVisits() {
return towerBridgeVisits;
}
}
What is this visitor? It's an interface that does something specific for each subclass:
public interface EmployeeVisitor {
void visit(EnglishEmployee employee);
void visit(FrenchEmployee employee);
}
And here is an example of it usage, compared to the usage of instanceof:
public class EmployeeService {
public void displayEmployeeWithUglyInstanceof(Employee employee) {
if (employee instanceof EnglishEmployee) {
EnglishEmployee english = (EnglishEmployee) employee;
System.out.println("An English employee that visited the tower bridge " + english.getTowerBridgeVisits() + " times");
}
else if (employee instanceof FrenchEmployee) {
FrenchEmployee french = (FrenchEmployee) employee;
System.out.println("A French employee that visited the eiffel tower " + french.getEiffelTowerVisits() + " times");
}
}
public void displayEmployeeWithVisitor(Employee employee) {
EmployeeVisitor visitor = new EmployeeVisitor() {
#Override
public void visit(EnglishEmployee employee) {
System.out.println("An English employee that visited the tower bridge " + employee.getTowerBridgeVisits() + " times");
}
#Override
public void visit(FrenchEmployee employee) {
System.out.println("A French employee that visited the eiffel tower " + employee.getEiffelTowerVisits() + " times");
}
};
employee.accept(visitor);
}
}
You might see that as overengineering, but in the case of Hibernate entities, it's actually very useful, because Hibernate uses dynamic proxies for lazy associations. So an employee might very well not be an EnglishEmployee nor a FrenchEmployee. In that case, instanceof will return false for both cases, and your code won't do anything. Whereas with the visitor, the proxy will delegate the call to the French or English employee it wraps, and everything will go smoothly.
Another advantage is that, if you add a SpanishEmployee, you will immediately see all the visitor implementations that must be modified to handle a spanish employee.

One possible trick goes:
public abstract class Employee {
// ...
FullTimeEmployee asFullTimeEmployee() {
return null;
}
}
public class FullTimeEmployee extends Employee {
// ...
#override
FullTimeEmployee asFullTimeEmployee() {
return this;
}
}

Related

How do I code an ID number whose first digit changes depending on the subclass created?

I'm working on an assignment in my computer science course and I am stuck on a certain part where I'm asked to generate ID numbers with specific rules and I am not sure how to go about it. Here are the exact instructions:
Phase 3: Item
Items are used in the system as a superclass for both Flight and Payloads. All Items are issued a unique identifier
within the system, for tracking. The rules for IDs are as follows:
• All ID numbers are 9 digits long
• The first digit changes based on the type of item
o Commercial Flights start with 1
o Industrial Flights start with 2
o Persons start with 3
o Cargo starts with 4
• The last 8 digits begin at 0 and increase by one for each item created
o That is, the first Item created will end in 0, the next will end in 1, and so on. Example: creating a
Commercial flight would be issued id 100000000, then a Person would be issued 300000001
respectively.
Consider where to add code in the hierarchy (Item, and its subclasses) to generate and store these IDs.
This is the code I tried, the class Item and its constructor:
public abstract class Item {
protected int id;
public Item() {
int commercialID = 100000000;
int industrialID = 200000000;
if( this instanceof Commercial){
id = commercialID;
commercialID++;
} else if (this instanceof Industrial) {
id = industrialID;
industrialID++;
}
}
I also tried making the id variable static but that changed nothing
Here are Commercial and Industrial too
public class Industrial extends Flight{
public Industrial(){
super();
}
}
public class Commercial extends Flight{
public Commercial(){
super();
}
}
Thank you.
You Item class is you top (abstract) class with 2 (abstract) subclasses: Payload and Flight
Item must define an abstract method that will return the offset in each concrete subclass.
Payload has 2 subclasses: Cargo and Person
Flight has 2 subclasses: CommercialFlight and IndustrialFlight
You must store the last generated id in a static field and increase it by one before to append it to the offset defined for each concrete class.
See example below:
public abstract class Item {
protected int id;
protected static int lastGeneratedId = 0;
protected Item() {
lastGeneratedId++;
this.id = 100000000 * getIdPrefix() + lastGeneratedId;
System.out.println(toString());
}
protected abstract int getIdPrefix();
#Override
public String toString() {
return "New " + getClass().getName() + " created with id " + id;
}
}
The two abstract sublasses:
Flight
public abstract class Flight extends Item {
public Flight() {
super();
}
}
Payload
public abstract class Payload extends Item {
public Payload() {
super();
}
}
And the concrete classes:
CommercialFlight
public class CommercialFlight extends Flight {
public CommercialFlight() {
super();
}
#Override
protected int getIdPrefix() {
return 1;
}
}
IndustrialFlight
public class IndustrialFlight extends Flight {
public IndustrialFlight() {
super();
}
#Override
protected int getIdPrefix() {
return 2;
}
}
Person
public class Person extends Payload {
public Person() {
super();
}
#Override
protected int getIdPrefix() {
return 3;
}
}
Cargo
public class Cargo extends Payload {
public Cargo() {
super();
}
#Override
protected int getIdPrefix() {
return 4;
}
}
And a class to test all this:
public class ItemTester {
public static void main(String[] args) {
new Cargo();
new IndustrialFlight();
new Cargo();
new CommercialFlight();
new IndustrialFlight();
new Person();
new Person();
}
}

Java factory but objects have slightly differrent attributes

I want to program a factory that creates two types of People which are "Employee" and "Entrepreneur". They both share the same basic "Person" attributes but they also implements their unique ones.
The problem is that if i want to return a method or an attribute that is not declared in the "Person" abstract class the program doesn't find it (since obviously I'm generating an object that is type "Person" and not specifically "Employee" or "Entrepreneur" ).
How do i tackle this problem?
This is the Demo class
public class Demo{
public static void main(String[] args){
PersonFactory pf = new PersonFactory();
Person p1 = pf.getPerson("Employee");
p1.presentation();
System.out.println(p1.getComplanyName());
}
}
This is the abstract class
public abstract class Person{
String name;
String surname;
abstract void presentation();
}
Those are the two concrete classes that extend Person
public class Entre extends Person{
int licenseNumber;
#Override
public void presentation(){
System.out.println("hi i'm an Entrepreneur");
}
public int licenseNumber(){
return licenseNumber;
}
}
public class Empl extends Person{
String companyName;
#Override
public void presentation(){
System.out.println("hi i'm an employee");
}
public String getCompanyName(){
return companyName;
}
}
Finally the Factory
public class PersonFactory{
public Person getPerson(String type){
if(type.equalsIgnoreCase("ENTREPRENEUR")){
return new Entre();
}
else if(type.equalsIgnoreCase("Employee")){
return new Empl();
}
return null;
}
}

Calling a method on every created object

I've been wondering is there any way to call a method for EVERY object of one specific class?
Let's say I have a class:
public class Employee {
private double salary;
private boolean hired;
public double getSalary() {return salary;}
public double setSalary(double x) {salary=x;}
public boolean getHired() {return hired;}
public boolean setHired(boolean check) {hired=check;}
}
then I declare another class that extends Employee, e.g. Boss (because Boss is an employee too, right)
so he inherits "gets" and "sets" from Employee and also has the possibility to fire employee:
public class Boss extends Employee {
public void fireTheGuy(Employee unluckyYou) {
boolean temp;
temp=false;
unluckyYou.setHired(temp);
unluckyYou.setSalary(0.0);
}
this allows in main:
public static void main(String args[])
{
Employee worker1 = new Employee();
Employee worker2 = new Employee();
Boss slacker = new Boss();
slacker.fireTheGuy(worker1);
slacker.fireTheGuy(worker2);
}
but what if I have like 100 employees and the Boss wants to fire them all? how this method should be called (is this even possible by some kind of loop?)
You could make all employees register themselves in a common static List. Then when the boss is told to fire everyone he just walks the list.
static List<Employee> allEmployees = new ArrayList<>();
public class Employee {
private double salary;
private boolean hired;
public Employee() {
// All employees must register themselves in the allEmployees list.
allEmployees.add(this);
}
public double getSalary() {return salary;}
public double setSalary(double x) {salary=x;}
public boolean getHired() {return hired;}
public boolean setHired(boolean check) {hired=check;}
}
public class Boss extends Employee {
public void fireTheGuy(Employee unluckyYou) {
unluckyYou.setHired(false);
unluckyYou.setSalary(0.0);
}
public void fireThese(Iterable<Employee> fireThem) {
for ( Employee e : fireThem ) {
fireTheGuy(e);
}
}
public void fireEveryone() {
fireThese(allEmployees);
}
}
This is an example of code of what you could do
List<Employee> employees=new ArrayList<Employee>();
employees.add(worker1);
employees.add(worker2);
for(Employee worker:employees){
slacker.fireTheGuy(worker);
}
But like mentionned in the comments you should try to understand all the concepts behind this example.

CompareTo of comparable does not take arguments other than Object type.

It seems odd that this is not working as I expected. I wrote a simple java class that implements Comparable interface and override the compareTo() method. However, It doesn't let me pass arguments of specific type other than Object. I looked on other guys' codes online which they did used other typed objects and I copied their code into eclipse and still I got the same error.
My question is; what I have to do to compare this object with object of type lets say Person. I do have the same issue with Comparator Interface (compare() method).
This code is the one I found it online.
public class Person implements Comparable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return this.age;
}
public String getName() {
return this.name;
}
#Override
public String toString() {
return "";
}
#Override
public int compareTo(Person per) {
if(this.age == per.age)
return 0;
else
return this.age > per.age ? 1 : -1;
}
public static void main(String[] args) {
Person e1 = new Person("Adam", 45);
Person e2 = new Person("Steve", 60);
int retval = e1.compareTo(e2);
switch(retval) {
case -1: {
System.out.println("The " + e2.getName() + " is older!");
break;
}
case 1: {
System.out.println("The " + e1.getName() + " is older!");
break;
}
default:
System.out.println("The two persons are of the same age!");
}
}
}
You need to use generics to provide a specific type.
public class Person implements Comparable<Person> { // Note the generic to Person here.
public int compareTo(Person o) {}
}
The Comparable interface is defined something like this,
public interface Comparable<T> {
public int compareTo(T o);
}
You can make use of generics to use custom object types. Change your class definition from
public class Person implements Comparable {
to
public class Person implements Comparable<Person> {
Now you should be able to pass Person object to your compareTo method as mentioned here:
#Override
public int compareTo(Person personToCompare){
Learn more about generics here:
https://docs.oracle.com/javase/tutorial/java/generics/types.html

How to implement a composite pattern in Java?

I want to implement a composite pattern in Java in order to map a software development organization. So, let's assume there are multiple project managers and multiple developers. Each developer is assigned to exactly one project manager and each developer is able to code in various programming languages. The project managers lead the developers and know exactly their workload.
I am not a hundred percent sure about this design pattern, but I think that it is the perfect use case for this scenario, isn't it?
The result should be as follows:
I want to query the project manager to check the workload of all developers which are able to code in a specific programming language, e.g. Java.
Here is what I have so far:
Employee.java:
public class Employee {
private String name = null;
public Employee() {
name = "Noob";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
ProgrammingLanguages.java:
public enum ProgrammingLanguages {
JAVA,
JAVASCRIPT,
C,
PHP,
SWIFT,
PYTHON
}
ProjectManager.java:
import java.util.ArrayList;
import java.util.List;
public class ProjectManager extends Employee {
private List<Employee> employeeList = null;
public ProjectManager() {
employeeList = new ArrayList<Employee>();
}
public List<Employee> getEmployees() {
return employeeList;
}
public void setEmployees(List<Employee> employees) {
employeeList = employees;
}
public int getTotalWorkload() {
int workload = 0;
for (Employee employee : employeeList) {
workload += employee.getWorkload(); // Error! Cannot resolve method 'getWorkload()'
}
return workload;
}
}
Developer:
import java.util.ArrayList;
import java.util.List;
public class Developer extends Employee {
private List<ProgrammingLanguages> languagesList = null;
private int workload = 0;
public Developer() {
languagesList = new ArrayList<ProgrammingLanguages>();
}
public void setLanguagesList(List<ProgrammingLanguages> languagesList) {
this.languagesList = languagesList;
}
public void addProgrammingLanguage(ProgrammingLanguages language) {
languagesList.add(language);
}
public List<ProgrammingLanguages> getLanguagesList() {
return languagesList;
}
public void setWorkload(int workload) {
this.workload = workload;
}
public int getWorkload() {
return workload;
}
}
Unfortunately, I get a compiler error in my ProjectManager class, any idea why?
Thanks in advance.
I am not a hundred percent sure about this design pattern, but I think that it is the perfect use case for this scenario, isn't it?
The GoF structure of Composite is as follows:
As you can see, Operation() is common in all elements. That would be your scenario's getWorkload() method.
However, it's somewhat inconsistent with the pattern in that it implies that a Manager has a workload that is composed of her employees. It's the contrary in real life, at least with a good manager. I would suggest changing the method name to something like getEffortUnderMyResponsibility(), to imply a responsibility for getting the work done, rather than actually doing the work. For programmers, it's true they actually do it; for managers, they are responsible for it getting done.
Yes, the composite pattern is indeed the right choice if you want to map tree structures. With reference to your example, the composite design pattern implies that your class Employee acts as a node, the class ProjectManager acts as a branch and the class Developer acts as a leaf. Within this context, the main advantage of the composite pattern is that it treats objects of your compositions uniformly. As a result, you can represent entire hierarchies of instances with this particular GoF design pattern.
You need the following participants:
The abstract class Employee must declare the interface of the composition and implements a common behaviour to a certain degree.
The ProjectManager class extends the abstract class Employee and implements a behaviour to treat Employee children, i.d. in your case ProjectManager or Developer instances.
The Developer also extends the abstract class Employee and represents a leaf which does not have any children.
I used your example code to demonstrate the composite pattern. Please note that it may vary from your desired outcome, but you can take it as a reference.
Employee.java (node):
package me.eckhart;
import java.util.List;
public abstract class Employee {
private String name = null;
public static final String OPERATION_NOT_SUPPORTED = "Operation not supported.";
public String getName() {
return name;
}
public Employee setName(String name) {
if (name == null) throw new IllegalArgumentException("Argument 'name' is null.");
this.name = name;
return this;
}
public Employee addEmployee(Employee employee) {
throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED);
}
public List<Employee> getEmployees() {
throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED);
}
public Employee setEmployees(List<Employee> employees) {
throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED);
}
public Employee setLanguagesList(List<ProgrammingLanguages> languagesList) {
throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED);
}
public Employee addProgrammingLanguage(ProgrammingLanguages language) {
throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED);
}
public List<ProgrammingLanguages> getLanguagesList() {
throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED);
}
/* Composite operations. */
public abstract int getWorkload(ProgrammingLanguages language);
public abstract Employee setWorkload(int workload);
}
ProjectManager.java (branch):
package me.eckhart;
import java.util.ArrayList;
import java.util.List;
public class ProjectManager extends Employee {
private List<Employee> employeeList = null;
public ProjectManager() {
this.employeeList = new ArrayList<>();
}
#Override
public Employee addEmployee(Employee employee) {
if (employee == null) throw new IllegalArgumentException("Argument 'employee' is null.");
this.employeeList.add(employee);
return this;
}
#Override
public List<Employee> getEmployees() {
return this.employeeList;
}
#Override
public Employee setEmployees(List<Employee> employeeList) {
if (employeeList == null) throw new IllegalArgumentException("Argument 'employeeList' is null.");
this.employeeList = employeeList;
return this;
}
/* Composite operations. */
public int getWorkload(ProgrammingLanguages language) {
int workload = 0;
for (Employee employee : employeeList) {
workload += employee.getWorkload(language);
}
return workload;
}
public Employee setWorkload(int workload) {
throw new UnsupportedOperationException(Employee.OPERATION_NOT_SUPPORTED);
}
}
Developer.java (leaf):
package me.eckhart;
import java.util.ArrayList;
import java.util.List;
public class Developer extends Employee {
private List<ProgrammingLanguages> languagesList = null;
private int workload = 0;
public Developer() {
this.languagesList = new ArrayList<>();
}
#Override
public Employee setLanguagesList(List<ProgrammingLanguages> languagesList) {
this.languagesList = languagesList;
return this;
}
#Override
public Employee addProgrammingLanguage(ProgrammingLanguages language) {
this.languagesList.add(language);
return this;
}
#Override
public List<ProgrammingLanguages> getLanguagesList() {
return this.languagesList;
}
/* Composite operations. */
public Employee setWorkload(int workload) {
if (workload < -1) throw new IllegalArgumentException("Workload cannot be negative.");
this.workload = workload;
return this;
}
public int getWorkload(ProgrammingLanguages language) {
if (this.languagesList.contains(language)) return workload;
return 0;
}
}
ProgrammingLanguages.java (enumeration):
package me.eckhart;
public enum ProgrammingLanguages {
JAVA,
JAVASCRIPT,
C,
PHP,
SWIFT,
PYTHON
}
I created a unit test to demonstrate how you can access the workload for one particular programming language.
EmployeeTest.java (JUnit 4.11):
package me.eckhart;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class EmployeeTest {
protected Employee projectManagerIt;
#Before
public void setUp() throws Exception {
Employee webDevSr = new Developer();
webDevSr.setName("Jane").addProgrammingLanguage(ProgrammingLanguages.JAVASCRIPT).addProgrammingLanguage(ProgrammingLanguages.PYTHON).setWorkload(10);
Employee webDevJr = new Developer();
webDevJr.setName("Alex").addProgrammingLanguage(ProgrammingLanguages.PHP).setWorkload(15);
Employee projectManagerWebDev = new ProjectManager();
projectManagerWebDev.setName("James").addEmployee(webDevSr).addEmployee(webDevJr);
Employee softwareDevSr = new Developer();
softwareDevSr.setName("Martin").addProgrammingLanguage(ProgrammingLanguages.C).addProgrammingLanguage(ProgrammingLanguages.JAVA).setWorkload(35);
Employee softwareDevJr = new Developer();
softwareDevJr.setName("John").addProgrammingLanguage(ProgrammingLanguages.JAVA).setWorkload(30);
Employee projectManagerBackend = new ProjectManager();
projectManagerBackend.setName("Tom").addEmployee(softwareDevSr).addEmployee(softwareDevJr);
Employee freelanceSoftwareDev = new Developer();
freelanceSoftwareDev.setName("Marco").addProgrammingLanguage(ProgrammingLanguages.JAVA).addProgrammingLanguage(ProgrammingLanguages.PYTHON).addProgrammingLanguage(ProgrammingLanguages.C).setWorkload(25);
Employee freelanceWebDev = new Developer();
freelanceWebDev.setName("Claudio").addProgrammingLanguage(ProgrammingLanguages.SWIFT).addProgrammingLanguage(ProgrammingLanguages.JAVASCRIPT).addProgrammingLanguage(ProgrammingLanguages.PHP).setWorkload(10);
Employee freelanceProjectManager = new ProjectManager();
freelanceProjectManager.setName("Angie").addEmployee(freelanceSoftwareDev).addEmployee(freelanceWebDev);
projectManagerIt = new ProjectManager();
projectManagerIt.setName("Peter").addEmployee(projectManagerWebDev).addEmployee(projectManagerBackend).addEmployee(freelanceProjectManager);
}
#Test
public void testComposite() throws Exception {
Assert.assertEquals(90, projectManagerIt.getWorkload(ProgrammingLanguages.JAVA));
Assert.assertEquals(20, projectManagerIt.getWorkload(ProgrammingLanguages.JAVASCRIPT));
Assert.assertEquals(60, projectManagerIt.getWorkload(ProgrammingLanguages.C));
Assert.assertEquals(25, projectManagerIt.getWorkload(ProgrammingLanguages.PHP));
Assert.assertEquals(10, projectManagerIt.getWorkload(ProgrammingLanguages.SWIFT));
Assert.assertEquals(35, projectManagerIt.getWorkload(ProgrammingLanguages.PYTHON));
}
}
The UML class diagram looks like this:
The code in the setUp() method of EmployeeTest.java implements the following tree structure:
The main disadvantage of the composite design pattern is that you need to restrict certain operations with runtime-checks, since clients usually do not know whether they are dealing with a ProjectManager (branch) or a Developer (leaf) instance.
The method getWorkload() is not defined in class Employee and you're trying to access it.
In order to solve the compilation error you should add this method to Employee - I would add it as abstract in order to force any (new) sub-class to implement it.
BTW, that's not composition-pattern - that's inheritance. You can (and should) read more about it.

Categories