1
public interface Foo {
}

public class ExtendedFoo implements Foo {
    public void myMethod() {
        System.out.println(1);
    }
}

public class AnotherExtendedFoo implements Foo {
    @Override
    public String toString() {
        return "hello world"
    }
}

public class UnknownImplementedFoo {
    public final Foo foo; // can be either ExtendedFoo OR AnotherExtendedFoo

    public UnknownImplementedFoo(ExtendedFoo f) {
        this.foo = f;
    }

    public UnknownImplementedFoo(AnotherExtendedFoo f) {
        this.foo = f;
    }
}

...
public void myTest() {
    ExtendedFoo f1 = new ExtendedFoo();
    AnotherExtendedFoo f2 = new AnotherExtendedFoo();

    UnknownImplementedFoo ifoo1 = new UnknownImplementedFoo(f1);
    System.out.println(ifoo1.foo.myMethod()); // can't access myMethod!

    System.out.println(ifoo1.type); // prints ExtendedFoo@21599f38
                                    // it knows which type of Foo it is
                                    // so why can't it call its custom methods?

    UnknownImplementedFoo ifoo2 = new UnknownImplementedFoo(f2);
    System.out.println(ifoo2); // prints hello world

}
...

The problem is shown at the end (myTest method), where I cannot access attributes/methods of the classes that extend the inteface.

Is there any workaround?

That is, I want UnknownImplementedFoo to take ANY class that implements Foo (ie. not just these 2), while still being able to access the public attributes/methods.

emihir0
  • 1,200
  • 3
  • 16
  • 39

4 Answers4

2

You are really fighting against the grain of the way a strongly typed languages like java works.

One of the purposes of interfaces is polymorphism by capturing common functionality among different classes.

You are asking for a way to access the non common particularities of a set of classes that share a common marker (empty) interface.

You can use reflection to interrogate class instances for type information and even to call methods, but I don't see how that will get you a workable solution.

You want to look into one of the gang of four patterns for addressing this situation. An example is the command pattern which abstracts away the need for a client to know about which methods are called on an object:

A Command class holds some subset of the following: an object, a method to be applied to the object, and the arguments to be passed when the method is applied. The Command's "execute" method then causes the pieces to come together.

Robert Moskal
  • 21,737
  • 8
  • 62
  • 86
  • I see. I guess visitor pattern could also work. Is there any advantage/disadvantage to using visitor pattern as opposed to command pattern? @RobertMoskal – emihir0 Oct 09 '16 at 14:30
  • There are a number of patterns I java that address this sort of issue. I can clearly see a solution with command, I don't have one in mind with visitor. Not to say there isn't. – Robert Moskal Oct 09 '16 at 14:32
  • 1
    Visitor, Command, Double Dispatch are all very similar.. and are used for slightly different circumstances. It really depends on what you are trying to model, something which is abstracted out of the question. – Chris K Oct 09 '16 at 14:37
  • Visitor is very useful when the interface itself is doing the dispatching, say when traversing a graph.. we could add a visit method to each node. The command pattern separates knowledge of the dispatch away from the original class, very useful for separating data and logic... an example of that would be writing a JVM byte code interpreter. – Chris K Oct 09 '16 at 14:42
2

Be wary of The Liskov Substitution Principle. An interface is a publicly declared contract for an object, and one should be able to swap out different implementations of the interface within the same bit of code without breaking the program/surprising side effects.

Java makes the situation of wanting to invoke a method that is not declared on the interface, but only one of the implementations difficult specifically because wanting to do so flags an OO design problem. Thus I strongly encourage you to redesign the classes that you are using so that all methods that are publicly required are declared on the interface.

That said, if you really must work around the problem (and there are situations where one may need to) then here some approaches that can be taken.

  • Approach one: use instanceof and casting (warning: this leads to fragile code and is often frowned upon by OO purists and people responsible for maintaining code after you)

    if ( x instanceof ExtendedFoo ) { ((ExtendedFoo) x).myMethod(); }

  • Approach two: Double Dispatch/Visitor Pattern/Command Pattern (warning: this leads to code that takes more effort to follow and understand and it only works when one wants to have different behaviours per class but it does have the advantage of offering more compile time safety than using instanceof and casting.. useful as a technique, but do not over use)

    Add a method 'public void visit( Visitor v )' to the interface Foo.

    Visitor should be declared something like this:

    public interface Visitor { public void visitExtendedFoo( ExtendedFoo f ); public void visitAnotherExtendedFoo( AnotherExtendedFoo f );
    }

    The implementations of visit(Visitor) are then coded to invoke the appropriate method on Visitor.

  • Approach three: Java 8 'default' keyword

    Java 8 now lets us add implementations to methods on interfaces. This helps us to add a method onto an interface without being forced to add a custom implementation to every implementation of that interface. Very useful when the method fits the OO design of the interface, but do not be tempted to add methods that do not belong conceptually to an interface as per standard OO advice.

  • Approach four: Reflection

    Use Java reflection to invoke the method at runtime. This is similar to using instanceof and casting, the key difference is that one performs the checks at compile time and the other at runtime.

Once again, only use any of the above techniques once you have ruled out, double ruled out and triple ruled out with peer review making changes to the OO design (specifically adding the method to the original interface and/or challenging the purpose and role of the interface in the first place).

Chris K
  • 11,622
  • 1
  • 36
  • 49
  • To be honest, this does not solve the problem. Despite it is flagged as answered. He asked for a way to call this method and this does not provide the solution. There is a way in Java to do this what he wants without any casting around. I am not sure why he should not use it. – mh-dev Oct 09 '16 at 14:45
1

You do one thing make a function signature to the Foo interface.

public interface Foo{
   public void myMethod();
}
  • But that would mean one would have to implement `myMethod` in ALL of the classes that extend `Foo`, which is not what is wanted =). – emihir0 Oct 09 '16 at 14:36
  • @emihir0 that is exactly what it means, yes. I suspect that the reasons why you do not want to do it comes down to a modelling challenge, which is difficult to advice you on because we do not have enough detail in the question. – Chris K Oct 09 '16 at 14:39
  • But as per my understanding here you are doing upcasting and in such occasion you have only one option which I told. Java enforce it to avoid error. Suppose foo=f2 and we call foo.myMethod(); which will give a run time exception. To avoid this Java enforce this rule – Siddhartha Sadhukhan Oct 09 '16 at 14:46
0

Use Java generics to get a type safe version.

public class UnknownImplementedFoo<FooType extends Foo> {
    public final FooType foo; // can be either ExtendedFoo OR AnotherExtendedFoo

    public UnknownImplementedFoo(FooType f) {
        this.foo = f;
    }
}

It seems that there are some problems with the proper understanding. Not sure why there are 2 downvotes without a comment.

Proper usage:

ExtendedFoo f1 = new ExtendedFoo();
AnotherExtendedFoo f2 = new AnotherExtendedFoo();

UnknownImplementedFoo<AnotherExtendedFoo> ifoo1 = new UnknownImplementedFoo<>(f2);
// syntax error
// ifoo1.foo.myMethod()); 

UnknownImplementedFoo<ExtendedFoo> ifoo2 = new UnknownImplementedFoo<>(f1);
// valid
ifoo2.foo.myMethod(); 
mh-dev
  • 5,264
  • 4
  • 25
  • 23
  • Added proper type safe usage since it seems that it is not clear (downvotes ~~) – mh-dev Oct 09 '16 at 14:40
  • This answer could be improved by including the pros/cons of this approach. I have taken it to be a variant of adding the method to the interface solution, which trades readability to avoid writing methods in multiple places. Java 8 offers the default method which would be cleaner. Both valid approaches for different circumstances. I have upvoted. – Chris K Oct 09 '16 at 14:52
  • Your trying to answer a question with patterns. That's fine, but inaccurate. Since patterns need to be converted into language and even framework specific solutions. The question is simply how can I do this and this is exactly the way it can be done. This can be applied in may real world scenarios. Your answer gave 2 approaches both do not solve the problem that was described. It was just your opinion that it should be done differently without knowing the real use-case. – mh-dev Oct 09 '16 at 14:57