views:

530

answers:

3

If I have two interfaces , both quite different in their purposes , but with same method signature , how do I make a class implement both without being forced to write a single method that serves for the both the interfaces and writing some convoluted logic in the method implementation that checks for which type of object the call is being made and invoke proper code ?

In C# , this is overcome by what is called as explicit interface implementation. Is there any equivalent way in Java ?

+6  A: 

No, there is no way to implement the same method in two different ways in one class in Java.

That can lead to many confusing situations, which is why Java has disallowed it.

interface ISomething {
    void doSomething();
}

interface ISomething2 {
    void doSomething();
}

class Impl implements ISomething, ISomething2 {
   void doSomething() {} // There can only be one implementation of this method.
}

What you can do is compose a class out of two classes that each implement a different interface. Then that one class will have the behavior of both interfaces.

class CompositeClass {
    ISomething class1;
    ISomething2 class2;
    void doSomething1(){class1.doSomething();}
    void doSomething2(){class2.doSomething();}
}
jjnguy
But this way , I cannot pass an instance of CompositeClass somewhere a reference of the interfaces ( ISomething or ISomething2 ) are expected ? I cannot even expect client code to be able to cast my instance to the appropriate interface , so am I not loosing something by this restriction ? Also note that in this way , when writing classes that actually implement the respective interfaces , we loose the benefit of having the code into a single class , which may be a serious impediment sometimes.
Bhaskar
@Bhaskar, you make valid points. The best advice I have is add a `ISomething1 CompositeClass.asInterface1();` and `ISomething2 CompositeClass.asInterface2();` method to that class. Then you can just get one or the other out of the composite class. There is no great solution to this problem though.
jjnguy
Speaking of the confusing situations this can lead to , can you give an example ? Can we not think of the interface name added to the method name as an extra scope resolution which can then avoid the collision/ confusion ?
Bhaskar
+3  A: 

If you are encountering this problem, it is most likely because you are using inheritance where you should be using delegation. If you need to provide two different, albeit similar, interfaces for the same underlying model of data, then you should use a view to cheaply provide access to the data using some other interface.

To give a concrete example for the latter case, suppose you want to implement both Collection and MyCollection (which does not inherit from Collection and has an incompatible interface). You could provide a "Collection getCollectionView()" and "MyCollection getMyCollectionView()" functions which provide a light-weight implementation of Collection and MyCollection, using the same underlying data.

For the former case... suppose you really want an array of integers and an array of strings. Instead of inheriting from both List<Integer> and List<String>, you should have one member of type List<Integer> and another member of type List<String>, and refer to those members, rather than try to inherit from both. Even if you only needed a list of integers, it is better to use composition/delegation over inheritance in this case.

Michael Aaron Safyan
+1  A: 

There's no real way to solve this in Java. You could use inner classes as a workaround:

interface Alfa { void m(); }
interface Beta { void m(); }
class AlfaBeta implements Alfa {
    private int value;
    public void m() { ++value; } // Alfa.m()
    public Beta asBeta() {
        return new Beta(){
            public void m() { --value; } // Beta.m()
        };
    }
}

Although it doesn't allow for casts from AlfaBeta to Beta, downcasts are generally evil, and if it can be expected that an Alfa instance often has a Beta aspect, too, and for some reason (usually optimization is the only valid reason) you want to be able to convert it to Beta, you could make a sub-interface of Alfa with Beta asBeta() in it.

gustafc