Cannot access the unique properties of a concrete class using polymorphism
design-patterns, java
Solution
You should have a look at the visitor pattern. You need to declare an interface ConnectionVisitor and add an method visit for each of your connection class in your hierarchy.
public interface ConnectionVisitor {
public int visit (Connection connection);
public int visit (SqlServerConnection sqlconnection);
public int visit (OracleConnection oracleConnection)
}
Now you need to add an accept method in your base class connection and that accepts a ConnectionVisitor and then calls visit on it. Your new Connection class will look something like
public abstract class Connection {
private int port;
private int ipAddress;
public Connection() {}
public String description() {
return "Generic";
}
public int accept(ConnectionVisitor visitor){
return visitor.visit(this);
}
}
Notice that the accept method does a dual dispatch. It dispatches on the base of the object on which it is called and the parameter that is passed to this method. This is at the heart of visitor pattern.
You can then implement the ConnectionVisitor interface to define any new functionality without changing your base class.
class DemoVisitor implements ConnectionVisitor{
public int visit(Connection connection){
System.out.println("Visiting Connection");
return 1;
}
public int visit(SqlServerConnection sqlServerConnection){
System.out.println("Visiting SqlServerConnection");
return 1;
}
public int visit(OracleConnection oracleConnection){
System.out.println("Visiting Oracle Connection");
return 1;
}
}
In your TestConnection class you can simply create a new connection object and then call accept method on that object passing a visitor object.
public class TestConnection {
public static void main(String[] args) {
ConnectionFactory factory = new ConnectionFactory("SQLServer");
Connection conn = factory.createConnection();
conn = factory.createConnection();
System.out.println(conn.description());
ConnectionVisitor visitor = new DemoVisitor();
System.out.println(conn.accept(visitor));
}
}
So now any child class specific functionality must not reside in connection class hierarchy instead they must be implemented in new visitors.
Note that this pattern is not going to fit as such in your scenario. One of the limitation of this pattern in that the return type for all the methods in visitor interface must be same. This pattern may or may not fit your needs but it is worth looking into your case as such. You will probably need to modify this pattern to fit your needs. And that is what patterns are all about looking into some common solutions and then modifying those solutions to fit into your problem.
Problem
I am using the factory pattern to create objects of different connections in `java version "1.7.0_60"` The problem I am facing is that each concrete class will have unique properties for that particular class. As the factory will use polymorpthism when it return the instance of the concrete class, I cannot access the unique properties. i.e. `getHostType()` is unique only for `SqlServerConnection`. The workaround I have done is to declare `getHostType()` abstract in the super class and implement it in each concrete class. However, I don't really want to do it that way as the more concrete classes I add that have their unique properties the more abstract methods I will have to include in the super class, and then implement them in each concrete class. I want to keep my factory pattern and the abstract super class. I am just wondering if there is any other way instead of having the abstract methods in the super class? Any design patterns I can include to get around this? ``` public abstract class Connection { private int port; private int ipAddress; public Connection() {} public String description() { return "Generic"; } /* Implement in every concrete class, even if the concrete type doesn't have that property */ public abstract int getHostType(); } public class SqlServerConnection extends Connection { private int sqlHostType; public SqlServerConnection() { sqlHostType = 5060; } @Override public String description() { return "Created a Sql Server connection type"; } @Override public int getHostType() { return sqlHostType; } } public class OracleConnection extends Connection { public OracleConnection() {} @Override public String description() { return "Created an Oracle connection type"; } } final public class ConnectionFactory { protected String mType; public ConnectionFactory(String type) { mType = type; } /* Create the connection we want to use */ public Connection createConnection() { if(mType.equals("Oracle")) { return new OracleConnection(); } else if(mType.equals("SQLServer")) { return new SqlServerConnection(); } else { return null; } } } public class TestConnection { public static void main(String[] args) { ConnectionFactory factory = new ConnectionFactory("SQLServer"); Connection conn = factory.createConnection(); conn = factory.createConnection(); System.out.println(conn.description()); /* need to access the getHostType() */ System.out.println(conn.getHostType()); } } ```