Reputation: 86845
I'm trying to create a Visitor<T>
that returns a certain strategy
for an instanceof object.
It already works, but I cannot get the Generics
typesafe. What am I missing i the following code:
class Base;
class Foo extends Base;
class Bar extends Base;
interface Visitor<T> {
T visit (Foo foo);
T visit (Bar bar);
}
interface Strategy<T> {
void action(T obj);
}
class FooStrategy implements Strategy<Foo> {
@Override
void action(Foo foo) {
//perform strategy action on foo
}
}
//References to generic type Strategy<T> should be parameterized
class MyVisitor implements Visitor<Strategy> {
//References to generic type Strategy<T> should be parameterized
@Override
Strategy visit(Foo foo) {
return new FooStrategy();
}
//References to generic type MyStrategy<T> should be parameterized
@Override
Strategy visit(Bar bar) {
return new BarStrategy();
}
}
In the class MyVisitor
eclipse keeps complaining that Strategy<T>
should be parameterized. What am I missing to make this generic construct typesafe
?
Update:
I want to use it like this:
Visitor<Strategy> visitor = new MyVisitor();
Strategy strat = drawable.accept(visitor);
//use the strategy
Base object; //may be a Foo or Bar or whatever
strat.action(object);
Upvotes: 1
Views: 693
Reputation: 11733
This isn't a Visitor. And even if it were, this is not a correct use for one. Visitor uses double dispatch; this does not have that.
Upvotes: 0
Reputation: 523544
You could put a ? extends Base
to the type parameter to indicate that it's a strategy of whatever type you don't care, but it must be a subclass of Base.
class MyVisitor implements Visitor<Strategy<? extends Base>> {
@Override
Strategy<? extends Base> visit(Foo foo) {
return new FooStrategy();
}
@Override
Strategy<? extends Base> visit(Bar bar) {
return new BarStrategy();
}
}
Visitor<Strategy<? extends Base>> visitor = new MyVisitor();
Strategy<? extends Base> strat = drawable.accept(visitor);
However, you are not allowed to call a strategy like that:
//use the strategy
Base object; //may be a Foo or Bar or whatever
strat.action(object); // <--- error.
because the action method effectively has a signature of
<U extends Base> void action(U object);
i.e. the type of the argument may require an arbitrary subclass of Base, and the only type which can be passed to any arbitrary subclass of Base is null
.
To solve this, simply make FooStrategy and BarStrategy implement Strategy<Base>
:
class FooStrategy implements Strategy<Base> { void action(Base obj) { ... } }
class BarStrategy implements Strategy<Base> { void action(Base obj) { ... } }
class MyVisitor implements Visitor<Strategy<Base>> {
@Override
Strategy<Base> visit(Foo foo) {
return new FooStrategy();
}
@Override
Strategy<Base> visit(Bar bar) {
return new BarStrategy();
}
}
Visitor<Strategy<Base>> visitor = new MyVisitor();
Strategy<Base> strat = drawable.accept(visitor);
Base object;
strat.action(object);
Upvotes: 2