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.
Related
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.
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?
I have the following
public abstract class MyData
{
private String sID;
public void setsID(String sID) {
this.sID= sID;
}
public String getsID() {
return sID;
}
}
This base class is being extended by 2 other classes
public class DataTypeOne extends MyData
{
private String sName;
public void setsName(String sName) {
this.sName= sName;
}
public String getsName() {
return sName;
}
}
public class DataTypeTwo extends MyData
{
private String sSummary;
public void setsSummary(String sSummary) {
this.sSummary= sSummary;
}
public String getsSummary() {
return sSummary;
}
}
I am initializing this class as follows
MyData oDataOne = new DataTypeOne();
MyData oDataTwo = new DataTypeTwo();
Reason for that is that I have a factory method which shall give me the class based on type (One or two)
With oDataOne & oDataTwo, I am able to access getsID() from the base class but not the getters & setters of the respective class.
How can I access those? I
You can't access a method that doesn't exist. All you've promised your Java compiler is that oDataOne and oDataTwo are MyData objects. Since the MyData class doesn't have the implementation-specific methods, you cannot ask Java to call those methods (since it doesn't think they exist).
If you want to access those methods, you need to either cast the object to a class that actually has the right methods, or you can add abstract method stubs to your base class, which will tell Java that those methods actually exist.
Type casting is simpler to write in the short term, but less clear, and you may run into more trouble down the road:
((DataTypeOne) oDataOne).getsName();
((DataTypeTwo) oDataOne).getsSummary(); // Throws ClassCastException!
Adding abstract stubs is more robust, but may not make sense if not all concrete subclasses should implement all abstract methods:
public abstract class MyData {
public abstract void setsName(String name);
public abstract String getsName();
public abstract void setsSummary(String summary);
public abstract String getsSummary();
}
public class DataTypeOne extends MyData {
public String getsName() {
// implement
}
public void setsName(String name) {
// implement
}
// Still have to implement these!!!
public String getsSummary() {
// raise an exception or something if appropriate
}
public void setsSummary(String summary) {
// raise an exception or something if appropriate
}
}
// Same for DataTypeTwo
Since you declared the variable as a MyData, you can only access the methods of MyData. You can get to the subclass methods by casting it to DataTypeOne or DataTypeTwo:
((DataTypeOne)oDataOne).getsName()
But you need to be sure it is of type DataTypeOne or you will get a ClassCastException
MyData oDataOne = new DataTypeOne();
this says, that your oDataOne object is of the type MyData. Even if it is created as a DataTypeOne, java can only be sure that it is defiantly a MyData instance.
If you are sure that the MyData instance is in reality also a DataTypeOne instance, you can cast and then access the DataTypeOne methods + the MyData methods.
To make sure that an object is of a specific type test:
if(oDataOne instanceOf DataTypeOne){
((DataTypeOne) oDataOne).getsName(); // this will return the Name if oDataOne is really of the type DataTypeOne
}
An object of type MyData has no knowledge of whether any other classes extends it or not, so there is no way to access members of those classes.
You will have to cast your object to the specific type to access the specific members.
If you find yourself in this situation, you can be pretty sure that your design is flawed. If you need to perform a specific action for each type of MyData extension, add a method, e.g specialAction() to the interface and hide the specifics in there. That eliminates the entire need to find out which subclass you are dealing with.
If I have a bunch of classes that all contain an Enum and EnumMap and I want to create a superclass for those classes.
public interface ColorEnum {
}
class ColorMarbles extends Toy {
enum MARBLE implements ColorEnum
{ BLUE, GREEN }
EnumMap<MARBLE, String> names = new EnumMap<MARBLE, String>(MARBLE.class);
//stuff
// fields
public void populate(ArrayList<String> designer) {
int i = 0;
for(MARBLE marble : MARBLE.values()) {
marble.name = designer.get(i);
i++;
}
}
}
class ColorBalloons extends Toy {
enum BALLOON implements ColorEnum
{ YELLOW, RED }
EnumMap<BALLOON, String> names = new EnumMap<BALLOON, String>(BALLOON.class);
//stuff
// fields
public void populate(ArrayList<String> designer) {
int i = 0;
for(BALLOON balloon : BALLOON.values()) {
balloon.name = designer.get(i);
i++;
}
}
}
How do I make create a superclass to have a generic EnumMap that contains an enum of type ColorEnum like this?
public abstract class Toy {
EnumMap<ColorEnum, String> names;
}
eidt: I realize that I was too vague with my example. Dogs are probably a bad example. I change it to something hopefully more clear.
What I have is a bunch of classes with methods like populate which populates the EnumMap. The names are in a predefined order. Instead of defining populate in every class, I'm hoping to be able to bring it to the Toy superclass so I don't have to keep copy-pasting in each new class type Toy.
Hopefully this will explain more what I'm looking for.
I have a feeling your design is needlessly overcomplicated.
With enums
If you don't require a class inheritance, you can work with enums directly as with top level classes.
public interface Animal {}
public enum Dog implements Animal {
HUSKY("Husky"), LAB("Labrador");
private final String name;
Dog(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Enums can declare fields, methods and implement interfaces like any other Java classes. Their only limitation is that their direct superclass is always java.lang.Enum and they can't be extended.
However every enum constant can have its own set of unique data passed to its constructor. It is even possible that each of the constants can override a common method of that enum with its unique implementation.
A nice tutorial explaining more about the full power of enums:
http://javarevisited.blogspot.cz/2011/08/enum-in-java-example-tutorial.html
Without enums
In case you need an actual class inheritance for sharing some common methods (for example from the Animal superclass), I still would drop the map approach and rather try something more OOP oriented:
public class Animal {
}
public abstract class Dog extends Animal {
public abstract String getName();
public static class Husky extends Dog {
#Override
public String getName() {
return "husky";
}
}
public static class Lab extends Dog {
#Override
public String getName() {
return "labrador";
}
}
}
One mechanism I have used for something like this is to extend a generic base class that has a generic parameter that allows you to pass the Enum details up to it.
This example defines a base Table class for database tables:
public class Table<Column extends Enum<? extends Column>> {
// Name of the table.
protected final String tableName;
// All of the columns in the table. This is actually an EnumSet so very efficient.
protected final Set<Column> columns;
/**
* The base interface for all Column enums.
*/
public interface Columns {
// What type does it have in the database?
public Type getType();
}
// Small list of database types.
public enum Type {
String, Number, Date;
}
public Table(String tableName,
Set<Column> columns) {
this.tableName = tableName;
this.columns = columns;
}
}
Now you can subclass this:
public class VersionTable extends Table<VersionTable.Column> {
public enum Column implements Table.Columns {
Version(Table.Type.String),
ReleaseDate(Table.Type.Date);
// Sadly all of this must be in ALL of your enums but most of the work can be pushed up to `Table`
final Table.Type type;
Column(Table.Type type) {
this.type = type;
}
#Override
public Type getType() {
return type;
}
}
public VersionTable() {
super("Versions", EnumSet.allOf(Column.class));
}
}
and make use of functionality in the parent class that handles your enum.
Note here I am passing an EnumSet to the Table constructor. I am sure you could change this to accommodate your EnumMap requirement if you decide an EnumSet is insufficient.
I have 2 classes
public class Customer{
...
public String getCustomerNumber();
...
}
public class Applicant{
....
private Customer c;
public Customer getCustomer(){ return c; }
...
}
When presented with a list of customers or applicants I want a function which iterates the list and does something with the CustomerNumber.
I've tried overloading the function
public void processCustomerNumbers(List<Customer> custList)
...
public void processCustomerNumbers(List<Applicant> appList)
...
but these are seen as duplicate methods... is there a nice way of doing this rather than just having 2 differently named functions?
If you make both classes implement a common interface,
interface CustomerNumber {
String getCustomerNumber();
}
public class Customer implements CustomerNumber {
...
public String getCustomerNumber();
...
}
public class Applicant implements CustomerNumber {
....
private Customer c;
public Customer getCustomer() { return c; }
public String getCustomerNumber() { return getCustomer().getCustomerNumber(); }
...
}
then you might be able to do what you want with just a single method:
public void processCustomerNumbers(List<? extends CustomerNumber> appList) {
for (Customer c: appList) {
processCustomerNumber(c.getCustomerNumber());
}
}
The thing about generics in Java is that generic types are erased at runtime, so both of these methods compile to the same signature. You will need to have separate method names, or check the type of the list elements at runtime.
One way to workaround this issue would be to define custom list types like this:
class CustomerList extends ArrayList<Customer> {
...
}
class ApplicantList extends ArrayList<Applicant> {
...
}
Then the following overloading would be legal:
public void processCustomerNumbers(CustomerList custList)
public void processCustomerNumbers(ApplicantList appList)
However, I don't think that this would be a good idea. For a start, it hardwires particular implementation classes into your application's APIs.
A better approach is to define a common interface for Customer and Applicant that allows you to process them with one processCustomerNumbers method. (As described at length in other answers.)
Generics have what is known as type erasure - List<Customer> and List<Applicant> are the same type, the compiler just places compile-time restrictions on what you can do with them.
You could check the type of the first object in the list and call a (differently-named) internal method based on that.
Use array instead.
public void processCustomerNumbers(Customer[] custList)
...
public void processCustomerNumbers(Applicant[] appList)
...
When you try to call these methods with a list, convert the list to array:
List<Customer> customers;
List<Applicant> applicants;
...
processCustomerNumbers(customers.toArray(new Customer[]{});
processCustomerNumbers(applicants.toArray(new Applicant[]{});
Before coming into the method names , the class hierarchy is little bit confusing...
public class Customer{
...
public String getCustomerNumber();
...
}
public class Applicant{
....
private Customer c;
public Customer getCustomer(){ return c; }
...
}
Why should applicant and Customer be
different objects ? Can you tell the
relation between these objects ?