Reputation: 3038
I have two classes, Foo
and Bar
, and an Algorithm
class that uses both.
class Foo {
void method(Bar bar) {
bar.otherMethod();
...
}
}
class Bar {
void method() {
...
}
void otherMethod() {
...
}
}
class Algorithm {
void run(Foo foo, Bar bar) {
foo.method(bar);
bar.method();
...
}
}
The algorithm part (run
method) is generic, and I want to be able to reuse it in other projects, involving other pairs of classes analogue to Foo
and Bar
, which I know will each have the methods named method
. However, I do not want to put the Bar.otherMethod
at interface level (because it is not a generic functionality that will be needed for other IFoo
and IBar
pairs).
For this reason, I defined two interfaces:
interface IFoo {
void method(IBar bar);
}
and
interface IBar {
void method();
}
and changed the signature of Algorithm.run()
in order to use these interfaces, into
void run(IFoo foo, IBar bar).
The problem is that now, in the Foo
class, I have to make a cast in order to use specific aspects from its associated Bar
class. A similar cast would probably have to be made when I would use another pair of classes (e.g. I might have Foo2
and Bar2
, where in Foo2.method
I would need to cast its IBar
parameter to Bar2
, in order to be able to use specific functionality).
class Foo implements IFoo {
void method(IBar bar) {
(Bar)bar.otherMethod();
...
}
}
In general, this cast is an indicator of bad design. Is there indeed a problem? What would be a better approach for my intention of having a generic Algorithm.run()
method?
Edit:
One relevant aspect is that the Foo
and Bar
implementations in practice will actually come in pairs. At some point I might have other classes, Foo2
and Bar2
, where Foo2.method
does not need to call Bar2.otherMethod
. In this case, the initial Foo
will not be compatible with Bar2
, but I am not interested in such use cases -- could this have been marked through a different design?
Edit2: Changed title and text to better express that I am interested to work with one pair of Foo
and Bar
classes at a time.
Upvotes: 0
Views: 179
Reputation: 4588
You may want to leverage generics. Perhaps you have:
interface Bar {
void frob();
}
interface Foo<T extends Bar> {
void frood(T bar);
}
Then when you write:
Foo<SomeBar> foo = // ...
SomeBar bar = // ...
foo.frood(bar);
the Foo
implementation knows that it has, not just any Bar
, but specifically a SomeBar
.
Upvotes: 1
Reputation: 4588
Do Foo
and Bar
need to be different types? It sounds like each Foo
and Bar
are tightly coupled. Maybe they ought to be combined.
Upvotes: 1
Reputation: 11609
Yes, casting IBar
to Bar
is contradictory: you use interfaces but want to rely on a fact that all IBar
implementations will be of type Bar
or it subtypes, which you can not guarantee.
In your scenario declaring otherMethod
in IBar
interface is a lesser evil.
Upvotes: 0
Reputation: 48268
In general, this cast is an indicator of bad design...
not really, interfaces are a really good way to split what a class do and how the class can do it more
read this for more details and or take a look to this post https://stackoverflow.com/a/384067/982161
Upvotes: -1