Employee Class
public class Employee {
protected String name;
protected String jobsheetnumber;
public Employee(String n,String j){
this.name = n;
this.jobsheetnumber = j;
}
public Employee(String name)
{
this.name = name;
}
public String getName() {
return name;
}
public String getJobsheetnumber() {
return jobsheetnumber;
}
public void setName(String name) {
this.name = name;
}
public void setJobsheetnumber(String jobsheetnumber) {
this.jobsheetnumber = jobsheetnumber;
}
}
Mechanic Class
public class Mechanic extends Employee{
public Mechanic(String name,String jobsheetnumber){
super(name,jobsheetnumber);
}
}
Supervisor Class
public class Supervisor extends Employee{
public Supervisor(String name){
super(name);
}
}
Company Class [snippet]
public class Company {
private String companyname;
private String companyaddress;
private String postalcode;
private String city;
private String country;
private String telephonenumber;
private String faxnumber;
private String province;
private Employee supervisor;
private Employee mechanic;
public Company(String companyname,String companyaddress,String postalcode,String city,String country,String telephonenumber,String faxnumber,String province,String supervisorname,String jobsheetnumber,String mechanicname)
{
this.companyname = companyname;
this.companyaddress=companyaddress;
this.postalcode = postalcode;
this.city=city;
this.country=country;
this.telephonenumber=telephonenumber;
this.faxnumber=faxnumber;
this.province=province;
supervisor = new Supervisor(supervisorname);
mechanic = new Mechanic(mechanicname,jobsheetnumber);
}
Employee Class is the superclass of both Mechanic and Supervisor class .. right now i am using the attributes of Employee i.e name and jobsheetnumber in the subclasses Mechanic and Supervisor Class
the code works fine .. but what if i want to add extended functionality in Mechanic and Supervisor ? then i cannot access those variables because the reference is to the Employee type object.
is this the correct use Of Polymorphism ? that we have to use super() as the constructor each time we create a reference of Supervisor/Mechanic Object ?
can we not use extended functionality inside Supervisor and Mechanic Class ?
If you want to call a superclass non-zero-arg constructor then yes, you have to call it explicitly. If the superclass constructor has no arguments then the call will be inserted for you.
The point of polymorphism is so that objects can take care of themselves without having to have the rest of the program micro-manage them, so the outside program refers to them by a reference with the type of an interface or superclass without having to know the exact concrete type. For instance all employees might have a work method, where that work takes a different form for a supervisor than it does for a mechanic; the work method would be overridden by the specific subclasses, and might call the specific methods on the subclasses. So the company can iterate through all the employees and call work on each of them, while work is defined differently for different subclasses of employee.
(In practice using subclasses to describe roles is too inflexible to work, since an employee could have multiple roles, or those roles can change over time. It's usually better to use composition, here assigning Role objects to an Employee.)
A better use of polymorphism would be the same interface (methods) for different implementations. So you can decide which implementation will be used in runtime.
To explain my point i will give a example using your classes.
public class Employee{
public void work(int hours){ doNothing();}
}
public class Supervisor extends Employee{
private Object pen;
private Object note;
#Override
public void work(int hours){
observations = superviseWorkers();
note.write(observations, pen);
}
}
public class Mechanic extends Employee{
private Tool tool;
private TaskBoard taskBoard;
#Override
public void work(int hours){
task = taskBoard.getPendent()
if(task.canSolveWithTool(tool))
{
solveTask(task, tool)
}
}
}
Using example:
employees = new List<Employee>();
employees.add(new Supervisor("foo"));
employees.add(new Mechanic("bar"));
foreach(employee in employees){
//you don't need to know which kind of employee you are treating here because you are only calling a behavior that all employees have.
employee.work(8);
}
If in many places in your code you are trying to figure out which object you are dealing with probably you are doing it wrong.
I used your classes in my examples to facilitate your understanding but as Nathan Hughes suggested in this case would be better to use composition instead of inheritance.
I will handle above scenario in two ways.
Solution 1: ( Interface as roles)
You can have "state" in Employee object and you can implement role as interface.
Employee will have all common attributes & methods. You can override base class method like doWork() in respective Employee implementations.
You can add specific behaviour of Mechanic, Supvervisor with use of interfaces.
public interface ISupervise{
public void doSupervise();
}
public class Supervisor extends Employee implements ISupervise{
public void doSupervise(){
}
}
public interface IMechanic{
public void doMechanicWork();
}
public class Mechanic extends Employee implements IMechanic{
public void doMechanicWork(){
}
}
Solution 2: (Decorate role)
Implement Decorator pattern for Employee to play multiple roles. Mechanic and Supervisor will decorate Employee behaviour. Refer to this example for better understanding of Decorator pattern.
Sample code can be found #
When to Use the Decorator Pattern?
Related
I have an abstract class called Person.
A person has multiple child classes e.g. Driver, Sorter, Manager.
Each of which has its unique methods, and the ones shared e.g. name/age/location, etc and so I then thought that an abstract parent-class would be the solution. (Person)
Yet now I face a new problem, What if a person is both?
Now I have an 'Object' which is a Driver but also a Sorter.
So when he/she calls in sick, Person has a method called reportSick()
But when object driver.reportSick() is being called, there is a chance that there is another object for the same Person that is a Sorter.
It looks strange to me to have 2 objects for the same thing (The person in this case)
What am I overlooking/doing wrong/misunderstanding?
You can go this way:
Make the interface(or abstract class if needed) Profession and implement your classes (Driver, Sorter, Manager) from it.
Make Person not abstract and add there field List<Profession>. And when you need some methods call it in cycle for each Profession.
You've discovered one of the fundamental limitations of inheritance: It creates a very tight coupling between parent and child. "A Sorter is a Person". Not "A Sorter is some other kind of Person", but literally "A Sorter is directly an extension of Person and nothing else".
You can use composition to make explicit who to call next in the "inheritance" chain.
public interface Person {
public void reportSick();
}
public class OrdinaryPerson implements Person {
public void reportSick() {
// An "ordinary" person does nothing when they report sick.
}
}
public class Driver implements Person {
private Person next;
public Driver(Person next) {
this.next = next;
}
public void reportSick() {
// Driver specific stuff goes here ...
this.next.reportSick();
}
}
// Then do the same for Sorter and Manager ...
Now, if a person is "just" a driver, you can represent them as
new Driver(new OrdinaryPerson())
This person is both a driver and an ordinary person (OrdinaryPerson is our null object; it has no actual behaviors to speak of, so we can use it to break our chain).
If a person is both a driver and a sorter, we can write
new Driver(new Sorter(new OrdinaryPerson()))
and assuming Driver and Sorter each call the inner reportSick method, they'll both get called when you call the method on this aggregate we've constructed.
Driver, Manager & Sorter are just special kind of service that any person is efficient with. It may be one or more.
So, best way to declare interfaces for them and declare method for each without body.
Now declare class which extends abstract class & implements one or more interfaces.
public abstract class Person {
private String name;
private int age;
private String location;
// Constructor (Must)
public Person(String name, int age, String location) {
this.name=name;
this.age=age;
this.location=location;
}
}
public interface Driver {
void isDriving(String name, int age, String location);
}
public interface Sorter {
void isSorting(String name, int age, String location);
}
public interface Manager {
void isManaging(String name, int age, String location);
}
public class Person1 extends Person implements Driver, Manager {
/*
Properties, Constructors & Getters/Setters
*/
#overrides
public void isDriving(String name, int age, String location) {
// Driving Function Body
}
#overrides
public void isManaging(String name, int age, String location) {
// Managing Function Body
}
}
What makes composition different from aggregation they are both declared as private, is it in composition example we are creating an object of Address class in constructor of Person, if it's then how this makes the Person object control/own the Address object.
public class Person {
private String firstName;
private String lastName;
private Address address;
//Composition example
public Person() {
address = new Address();
}
public Address getAddress() {
return address;
}
}
Employee Class
public class Employee {
private String firstName;
private String lastName;
private int age;
//Aggregation Java example
private Address address;
public void setAddress(Address address) {
this.address = address;
}
public Address getAddress() {
return address;
}
}
Well, let me first start by explaining the differences between Aggregation and Composition.
Aggregation:
1. A child in an Aggregation relationship can exist independently of the parent
2. Aggregation can be read as "HAS A"
Example: If we have a class Wheel, the relationship between the class Wheel and Car is an Aggregation: "A car has four wheels". A Wheel can exist out of the context of a car.
Composition:
1. A child in an Composition relationship cannot exist independently of the parent. In other words, there's no sense of for the child class to exist if it cannot be hosted into the parent class.
2. Composition can be read as IS PART OF
Example: If we have a class Human, the relationship between the class Heart and Human is composition. You never seen a heart hanging out by itself, don't you? Hence, the need for Composition.
In Java we represent the Composition relationship using private final
class Human { private final Heart heart; }
While Aggregation would be just:
class Wheel { ... }
class Car { private List<Wheel> wheels; }
Now let's say, we would like to remove an object of class Human (taking into account he is not an organ donor) completely, the Composition relationship forces us to destroy the instance of the heart related to that human being. In Aggregation it is not the case, the wheels can be used by another car if the instance of the car they used to belong to got wrecked.
I hope this helps.
Beginner question - how do I avoid repeating code in sibling classes, where each has its own different version of the same field?
See example below: can I somehow move the getName() method (as well as far more complex methods) to the parent class?
public abstract class Car {
public abstract String getName();
}
public class PassengerCar extends Car {
private String name = "Passenger Car";
#Override
public String getName() { return name; }
}
public class CoalCar extends Car {
private String name = "Coal Car";
#Override
public String getName() { return name; }
}
You can, for example: create a constructor in the parent class which takes a name, and specify that name in the constructor of the child classes:
abstract class Car {
private String name;
public Car(String name) {
this.name = name;
}
public String getName() { return name; }
}
class PassengerCar extends Car {
public PassengerCar() {
super("Passenger Car");
}
}
class CoalCar extends Car {
public CoalCar() {
super("Coal Car");
}
}
Which then can be used like this:
Car passenger = new PassengerCar();
System.out.println(passenger.getName());
This prints out:
Passenger Car
#Mark's answer is the solution, but let me add a bit of background to it.
Simple rule of thumb: if you want something that all subclasses have in common, place it into the parent class.
What do you have?
a field called name used by all subclasses (it doesn't matter that the values are different, see below),
a getter called getName() used by all subclasses,
an initial value "Passenger Car" for all PassengerCar instances,
an initial value "Coal Car" for all CoalCar instances.
So, the name field and the getName() method go into Car, and the different initial values for that field go into the constructors of PassengerCar and CoalCar.
'Making the class field/property private' - is one of the best practice in OOP. To access the private field/property we can use public getter method. But only writing the getter method may not enough according to this blog(Please see Quote 2). It suggests returning a clone of the field/property (if it is a reference type) from the getter method. By following this approach we can make the field/property unmodifiable. Please see the code below -
public class Department{
Employee admin;
...
...
...
public Employee getAdmin(){
return admin.clone();
}
}
So from now the 'admin' is unmodifiable by the outer world if we don't use any setter. This approach looks pretty nice. But I hardly found any code which implements this approach. Is there any drawbacks of using this approach which may defeats the benefit of using this approach?
Thanks in advance.
The main drawback to this approach is the need to make a clone every time you get an object, which is not ideal, because ideally you prefer your getter to be lightweight.
There are two approaches that achieve similar effect without cloning:
Making Employee immutable, and
Giving Employee an immutable interface
The first approach is self-explanatory and is very efficient, but it is not always practical, especially in situations when your object represents state that needs to be shared in place.
The second approach is simple, too: rather than making Employee a class, make it an interface with only getters, make a class EmployeeImpl that implements Employee, and has getters and setters, and use the class when you need mutability.
public interface Employee {
String getFirstName();
String getLastName();
}
public class EmployeeImpl implements Employee {
private String firstName;
private String lastName;
public String getFirstName() {return firstName;}
public String getLastName() {return lastName;}
public void setFirstName(String name) {firstName = name;}
public void setLastName(String name) {lastName = name;}
}
This approach can be defeated by casting to a class, but most of the time it is OK.
If you are in a hostile environment where any modification to the actual object would be extremely harmful - say, you are exposing some API for your service that everyone could download and use, you would have to go for the full clone approach that you have described. However, situations like this are relatively rare.
Note: I changed this answer since it was first posted. The first solution I suggested had problems with inheritance which are now solved.
Cloning the objects returned is, generally, a very bad option. Unless the objects are very simple, or unless your application is not very complex, all this cloning will very likely introduce a significant overhead.
An alternative for your specific case is to have an interface called Employee that only offers getters. You can then also define the MutableEmployee class that implements Employee and also offers setters.
interface Employee {
public String getName();
public float getSalary();
}
class MutableEmployee implements Employee {
private String name;
private float salary;
#Override
public String getName() {
return name;
}
#Override
public float getSalary() {
return salary;
}
public void setSalary(float salary) {
super.salary = salary;
}
public void setName(String name) {
super.name = name;
}
}
Your Department class would then modified like this:
class Department {
private MutableEmployee admin;
public Employee getAdmin() {
return (Employee) admin;
}
public MutableEmployee getMutableAdmin() {
return admin;
}
}
Defining subclasses of MutableEmployee
When you want to create a subclass of MutableEmployee, like MutableGraphicDesigner, you will need to define the following:
interface GraphicDesigner extends Employee
class MutableGraphicDesigner extends MutableEmployee implements GraphicDesigner
I'm having an issue that I can't find the right way to resolve by myself.
Basically I have two objects Object1 & Object2 where both of these have two properties of the same type:
public class Object1 {
...
private String name;
private String description;
...
Object1 () {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
public class Object2 {
...
private String name;
private String description;
...
Object2 () {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
Now obviously I made them properties as strings here in the example but in reality they're other types.
NOTE: Object1 and Object2 are actually generated classes from XML models that I need for SOAP servces. So I can't modify them.
In some point in my code I have to access say the 'name' property of either Object1 or Object2 depending on different factors. This point is an event handler so in a certain moment of time it catches an event called with Object1 and other times with Object2.
My guess was to make a single class that would enclose both these types and expose one single "name" property and one single "description" property.
What would a standard way of doing this be?
There basically are two ways to do this:
Use a common interface that expose the getters and setters. Then let both classes implement that interface and let the handler use it.
If possible (both objects don't already extend other superclasses) you could use an abstract superclass and put the properties as well as the getters and setters there. The handler then uses that superclass.
Note that both approaches can be combined, i.e. use an interface for the handler and use an abstract superclass that implements that interface as an adapter class, i.e. you could extend that adapter when possible or just implement the interface when extending the adapter is not possible.
Example:
interface Common {
String getName();
}
abstract class CommonAdapter implements Common {
String name;
String getName() {
return name;
}
//setter as well
}
//just extend the adapter and enjoy
class Object1 extends CommonAdapter {
//specific code for Object1
}
//extending not possible, so implement the interface directly
class Object2 extends SomeOtherClass implements Common {
String name;
String getName() {
return name;
}
}
class Handler {
void handle( Common c ) {
c.getName();
...
}
}
Update:
If the classes are generated, you could create those objects as wrappers and delegate all calls to the actual class, e.g.
class Object1CommonWrapper implements Common {
Object1 delegate;
String getName() {
return delegate.getName();
}
}
make an abstract class and let both classes extend from it
Use interface or abstract class
public interface CommonObject {
//gettter and setter
}
public Class Object1 implements CommonObject { ... }
public Class Object2 implements CommonObject { ... }
public Class MainClass {
public void someMethod() {
if(someCondition) {
CommonObject obj1 = new Object1();
//use obj1
} else {
CommonObject obj2 = new Object1();
//use obj2
}
}
}
Use factory pattern
it depends a bit on the behaviour of said methods. So if:
Both Object1/ Object2 have the absolut identical code for those methods i would go with inheritance, have a superclass that defines those fields/ methods and the two objects extend it.
Both Object1/ object2 must have the same method signature but have to handle the internal logic in different ways i would go with a interface defining the method signature that both Object1/2 must implement.
You can define an interface that both Object1 and Object2 implement. The interface would include the methods that you need to call, but each class can implement them in its own way.
For example, it might look something like this:
public interface Describable {
String getName();
String getDescription();
}
public class Object1 implements Describable {
... implements the methods in some way
}
public class Object2 implements Describable {
... implements the methods in another way
}
With that, whatever code needs to deal with both of these types of objects can refer to them as Describable and take advantage of polymorphism. For example:
Describable eventObject = ...get the object...
eventObject.getName();
eventObject.getDescription();
Or even something like:
public void handle(Describable describable) {
describable.getDescription();
... more stuff...
}
That code doesn't know (or care) what type of object is actually passed in to the method, only that it can interact with it as a Describable.
This is a common idiom in Java and OO design in general. The core libraries use it all over the place.
By the way, inheritance (ie, using a common base super class) is another option. Just be aware that the technique of implementation inheritance has some trade-offs and is often abused/misused. For example see this discussion.