danbanica
danbanica

Reputation: 3038

Working with pairs of classes that implement a pair of interfaces

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

Answers (4)

djeikyb
djeikyb

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

djeikyb
djeikyb

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

AdamSkywalker
AdamSkywalker

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

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

  • they are ideal for defining mixins
  • they allow the construction of nonhierarchical type frameworks
  • they enable safe, powerful functionality enhancements via wrapper classes

read this for more details and or take a look to this post https://stackoverflow.com/a/384067/982161

Upvotes: -1

Related Questions