I have now put another rephrased version of original question as requested by the user in the comments with class names mimicking real world scenario of postal office (though I dont know how real world the rephrased example is). Original question had abstract/generalized class names. Also uploaded the correct code for both.
Rephrased Question
Design Requirements
- Postage and PostageLot: We run a postal office. So we have
class Postage
andinterface PostageLot
. - Classifying postage lot based on required speed of delivery: There is
class SpeedPostageLot
andclass NormalPostageLot
that implementinterface PostageLot
. - Classifying postage lot based on care to be taken:
- There are
interface ExecutivePostageLot
andinterface PublicPostageLot
.ExecutivePostageLot
is given extra care thanPublicPostageLot
. For illustration in code, I considered onlyExecutivePostageLot
and did not wrotePublicPostageLot
, so we will not write corresponding sub-classes forPublicPostageLot
- Both executive and public postages can be speed or normal postage. Thus I created subclasses of
SpeedPostageLot
andNormalPostageLot
that implementExecutivePostageLot
:ExecutiveSpeedPostageLot
andExecutiveNotmalPostageLot
. (Same in case for public postages:PublicSpeedPostageLot
andPublicNormalPostageLot
) - There is also
ExecutivePostage
class
- There are
- There is also
CommonSpeedPostageProcessor
which contains common logic to processSpeedPostageLot
which can be used by bothExecutivePostageProcessor
andPublicPostageProcessor
when they deal withSpeedPostageLot
. The methods ofCommonSpeedPostageLotProcessor
should return values of type which can be cast toExecutiveSpeedPostageLot
andPublicSpeedPostageLot
. I felt this should bePostageLot
orSpeedPostageLot
since it does not have any connotation of care-to-be taken (executive or public) attached to it. But this is not working as can be seen in below code.
Code
public class Postage {}
public interface PostageLot<T extends Postage> {}
public abstract class NormalPostageLot<T extends Postage> implements PostageLot<T>{}
public abstract class SpeedPostageLot<T extends Postage> implements PostageLot<T>{}
public interface ExecutivePostageLot extends PostageLot<ExecutivePostage> {}
public class ExecutiveSpeedPostageLot extends SpeedPostageLot<ExecutivePostage> implements ExecutivePostageLot {}
public class ExecutiveNormalPostageLot extends NormalPostageLot<ExecutivePostage> implements ExecutivePostageLot {}
public class ExecutivePostage extends Postage { }
public class CommonSpeedPostageProcessor
{
PostageLot<Postage> speedPostageProcessor1()
{
SpeedPostageLot<Postage> obj = null;
return obj;
}
SpeedPostageLot<Postage> speedPostageProcessor2()
{
SpeedPostageLot<Postage> obj = null;
return obj;
}
}
public class ExecutivePostageLotHandler {
public static void main(String[] args) {
CommonSpeedPostageProcessor logic = new CommonSpeedPostageProcessor();
ExecutivePostageLot obj = logic.method1EntitySetProcessor1(); //Type mismatch: cannot convert from PostageLot<Postage> to ExecutivePostageLot
ExecutivePostageLot obj2 = logic.method1EntitySetProcessor2(); //Type mismatch: cannot convert from SpeedPostage<Postage> to ExecutivePostageLot
ExecutiveSpeedPostageLot obj3 = logic.method1EntitySetProcessor1(); //Type mismatch: cannot convert from PostageLot<Postage> to ExecutiveSpeedPostageLot
ExecutiveSpeedPostageLot obj4 = logic.method1EntitySetProcessor2(); //Type mismatch: cannot convert from SpeedPostage<Postage> to ExecutiveSpeedPostageLot
}
}
(The zip of the eclipse project can be found here)
I understand those typecasts are invalid, but then where in design I made mistake? Primarily I feel that I am doing it right, its just that CommonSpeedPostageProcessor
needs to be parameterized with generic type parameter. But I am not able to guess exactly how do I do it. How should I generic-type-parameterize CommonSpeedPostageProcessor
?
Or I am simply over complicating the things?
Orignal Question
I am stuck while designing a class hierarchy for our application. Am not able to find any solution for this design constraints scenario.
Design requirements
(Names of classes and interfaces are over generalized to avoid unnecessary confusion due to domain specific names).
- Entity and EntitySet: We have organization wide
Entity
class and an interface identifying set of entitiesEntitySet
which enforces basic methods needed to deal with specific type of entity we deal with in our organization. - Method specific entity sets (Method1EntitySet and Method2EntitySet): Now there are two main methods to process this entity set. Each method defines class that implements
EntitySet
:Method1EntitySet
andMethod2EntitySet
. - Module specific interfaces and classes:
- Now we have different modules that are developed by different developer groups. All these modules need to use both
Method1EntitySet
andMethod2EntitySet
, however they also want these classes to have some common module specific methods. So they define interface containing module specific methods, sayModule1EntitySet
and - Each module also defines another pair of classes
Module1Method1EntitySet
andModule1Method2EntitySet
, both extending corresponding method specific classes (i.e.Method1EntitySet
andMethod2EntitySet
respectively) and implementing module specific interface (i.e.Module1EntitySet
). - Also each module defines its own entity
Module1Entity
- Now we have different modules that are developed by different developer groups. All these modules need to use both
- The common logic: I want to have a class (
CommonMethod1EntitySetLogic
) which will contain common functionality (to be used by all modules) of processingMethod1EntitySet
. All modules dealing withMethod1EntitySet
will use this common class. Thus the methods inCommonMethod1EntitySetLogic
class should return value of type which can be cast toModuleXMethod1EntitySet
orModuleXEntitySet
for anyModuleX
from which the mothods are called. I felt this type of the returned values can beEntitySet
orMethod1EntitySet
as they are not module specific. But this is not working as can be seen in below code.
Note: In all above class names, I have omitted the generics type specification to not cause confusion about my design requirements. But this might have lead to incorrect question. So I am providing the code below.
Code
public class Entity { }
public interface EntitySet<T extends Entity> { }
public abstract class Method1EntitySet<T extends Entity> implements EntitySet<T>{}
public abstract class Method2EntitySet<T extends Entity> implements EntitySet<T>{}
public class Module1Entity extends Entity{}
public interface Module1EntitySet extends EntitySet<Module1Entity>{}
public class Module1Method1EntitySet extends Method1EntitySet<Module1Entity> implements Module1EntitySet{}
public class Module1Method2EntitySet extends Method2EntitySet<Module1Entity> implements Module1EntitySet{}
public class CommonMethod1EntitySetLogic
{
EntitySet<Entity> method1EntitySetProcessor1()
{
Method1EntitySet<Entity> obj = null;
return obj;
}
Method1EntitySet<Entity> method1EntitySetProcessor2()
{
Method1EntitySet<Entity> obj = null;
return obj;
}
}
Now that all main classes given above, below is where I am getting compile time errors as specified in comments:
public class Module1 {
public static void main(String[] args) {
CommonMethod1EntitySetLogic logic = new CommonMethod1EntitySetLogic();
Module1EntitySet obj = logic.method1EntitySetProcessor1(); //Type mismatch: cannot convert from EntitySet<Entity> to Module1EntitySet
Module1EntitySet obj2 = logic.method1EntitySetProcessor2(); //Type mismatch: cannot convert from Method1EntitySet<Entity> to Module1EntitySet
Module1Method1EntitySet obj3 = logic.method1EntitySetProcessor1(); //Type mismatch: cannot convert from EntitySet<Entity> to Module1Method1EntitySet
Module1Method1EntitySet obj4 = logic.method1EntitySetProcessor2(); //Type mismatch: cannot convert from Method1EntitySet<Entity> to Module1Method1EntitySet
}
}
I understand those typecasts are invalid, but then where in design I made mistake? Primarily I feel that I am doing it right, its just that CommonMethod1EntitySetLogic
needs to be parameterized with generic type parameter. But I am not able to guess exactly how do I do it. How should I generic-type-parameterize CommonMethod1EntitySetLogic
?
Or I am simply over complicating the things?
(The zip of the eclipse project can be found here.)
Method1
,Method2
,Module1
, etc to concrete, everyday concepts, such as Customer, Sell, Payment, etc, and their sets and modules accordingly.