Reputation: 585
Consider the following class design:
public class SuperType { };
public class SubType1 extends SuperType { };
public class SubType2 extends SuperType { };
public class SubType3 extends SuperType { };
public class Tuple {
SuperType t1;
SuperType t2;
public Tuple(SuperType t1, SuperType t2) {
this.t1 = t1;
this.t2 = t2;
}
public void DoSomething1() {
if((t1 instanceof SubType1) && (t2 instanceof SubType3))
switch(t1, t2);
else if((t1 instanceof SubType2) && (t2 instanceof SubType1))
t1.DoSomething();
else if( ... ) {
t1.DoSomething();
t2.DoSomething();
}
else if( ... )
// ...
}
public void DoSomething2() {
// basically the same
}
}
Since the action is dependent on two types I cant avoid the instanceof operator by moving the method to the subtypes. Is there a way I can improve my design so I can avoid using instanceof?
I know there are a lot of similar questions here, but I'd like to avoid the use of a visitor, because I have around twenty DoSomething()-Methods which would result in 9*20 implementations of visit().
Upvotes: 0
Views: 149
Reputation: 2079
Here an simple solution option you can use it, using Generics
for the type safe & Polymorphism
to do the actions behavior in each of subclass
interface SuperType<T> { void doAction(); };
class SubType1 implements SuperType<SubType1> { public void doAction(){} };
class SubType2 implements SuperType<SubType2> { public void doAction(){} };
class SubType3 implements SuperType<SubType3> { public void doAction(){} };
class Tuple {
//if((t1 instanceof SubType1) && (t2 instanceof SubType3))
//passing params rather than instanceof checking
public void doSomething1CaseOne(SuperType<? extends SubType1> t1, SuperType<? extends SubType3> t3) {
if(t1 == null || t3 == null) {
throw new NullPointerException("Null Params!");
}
/**
* the method action here
* example: switch(t1, t2);
*/
}
//if((t1 instanceof SubType2) && (t2 instanceof SubType1))
public void doSomething1CaseTwo(SuperType<? extends SubType2> t2, SuperType<? extends SubType1> t1) {
if(t2 == null || t1 == null) {
throw new NullPointerException("Null Params!");
}
/**
* the method action here
* example: t1.doAction();
*/
}
... others methods
}
Now here an example for passing valid/invalid params to the method:
Tuple tuple = new Tuple();
SuperType<SubType1> t1 = new SubType1();
SuperType<SubType2> t2 = new SubType2();
SuperType<SubType3> t3 = new SubType3();
tuple.doSomething1CaseOne(t1, t3); //valid typesafe compilation time
tuple.doSomething1CaseOne(t1, t2); //invalid typesafe compilation time
tuple.doSomething1CaseTwo(t2, t1); //valid typesafe compilation time
tuple.doSomething1CaseTwo(t1, t2); //invalid typesafe compilation time
Upvotes: 0
Reputation: 59358
The proper way to do this in an OO language is using a pattern called "double-dispatch" (Googlable, but wikipedia's page on it is not great).
An "append" method makes a good example:
class Super
{
abstract void appendTo(Super target);
abstract void append(Sub1 source);
abstract void append(Sub2 source);
}
class Sub1
{
void appendTo(Super target)
{
target->append(this); //calls the Sub1 overload
}
void append(Sub1 source)
{
... this is Sub1, source is Sub1 ...
}
void append(Sub2 source)
{
... this is Sub1, source is Sub2 ...
}
}
class Sub2
{
void appendTo(Super target)
{
target->append(this); //calls the Sub2 overload
}
void append(Sub1 source)
{
... this is Sub2, source is Sub1 ...
}
void append(Sub2 source)
{
... this is Sub2, source is Sub2 ...
}
}
Upvotes: 1