Java – How to design an extensible type infrastructure with dependencies among each other

factoryinteractioninterfacejavamodeling

My application is an editor for connecting "modules" (through module ports). Ports have port types. Each port type has it's associated comparator. Two types are compatible if their attributes satisfy rules implemented in the comparator.

I want users to extend the application by implementing new port types and rules how to connect them (through the eclipse extension point infrastructure).

This implies that during runtime I can only interact with the port type interfaces. No concrete classes are known. All concrete implementations are returned by a factory.

I implemented this two interfaces:

public interface IPortType {
    [many attributes]
}
public interface IComparator {
    public boolean isCompatible(IPortType source, IPortType target);

    // more interaction methods!
}

My current solution is a bit ugly, since the generic isCompatible(IPortType source, IPortType target) method is a kind of delegate and has to be rewritten in all subclasses. Simply overloading the isCompatible() method does not work here.

But a bigger disadvantage is the violation of the open-closed-principle: One must extend all concrete Comparator classes when a new type should be supported. But how to keep the number of rule classes low, when there are more interactions between types like conversion, etc.? My intention was to keep all rules for one type in one class.

A concrete Comparator example:

public class ATypeComparator implements IComparator {

    public boolean isCompatible(IPortType source, IPortType target) {
        if (!(source instanceof AType))
            return false;
        if (target instanceof BType)
            return isCompatible(source, (BType) target);
        if (target instanceof CType)
            return isCompatible(source, (CType) target);
    }

    public boolean isCompatible(AType source, BType target) {...}
    public boolean isCompatible(AType source, CType target) {...}
}

How would you solve this problem?

Thanks for any suggestions!

Best Answer

I don't think it is right to an IPortType implementation decide whether it is compatible with other IPortType implementations. That's just not part of its responsibility.

A simple solution would be to create a single, public static method, for instance in a class PortTypeManager, that knows whether two IPortType implementation are compatible. That way, you can always add a new type and you only have to change logic in one place to accommodatie that new type.

However, in the end, this will also not be enough, because the number of cases that method should cover grows like n^2. You need to supply each IPortType implementation with a method like getVersion() or getSignature(), which returns a piece of data you can compare against a similar piece of data, to decide whether two implementations are compatible.