Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I wonder if it is possible to require that a java method parameter is of any type from finite set of types. For example - I am using a library where two (or more) types have common methods, but their lowest common ancestor in the type hierarchy is Object. What I mean here:

   public interface A {
      void myMethod();
   }

   public interface B {
      void myMethod();
   }
...
   public void useMyMethod(A a) {
      // code duplication
   }

   public void useMyMethod(B b) {
      // code duplication
   }

I want to avoid the code duplication. What I think of is something like this:

   public void useMyMethod(A|B obj){
      obj.myMethod();
   }

There is similar type of syntax in java already. For example:

  try{
     //fail
  } catch (IllegalArgumentException | IllegalStateException e){
     // use e safely here
  }

Obviously this is not possible. How can I achieve well designed code using such type of uneditable type hierarchy ?

share|improve this question
    
As you have no common interface, how should your compiler check that the two or more classes have a common "interface"? The problem is also that the code you define as "duplication" is no duplicate according to the program code as you have two different class hierarchies - the code only looks the same but works on completely different data structures. –  Smutje 4 hours ago
    
This is easy in Scala, but that probably doesn't help you. All I can suggest is making a wrapper for one interface that implements the other (or wrappers for both that implement the same interface). –  lmm 4 hours ago
2  
Since you've tagged it for “design patterns”, the adapter pattern comes to mind. But that requires you to code a wrapper for each of those types. Without doing that, I'm afraid that there will not be a statically type-safe solution to this. At least, I would be surprised if there were. –  5gon12eder 4 hours ago

8 Answers 8

Try using Adapter design pattern.

Or, if it's possible, add some base interface:

public interface Base {
    void myMethod();
}

public interface A extends Base {}
public interface B extends Base {}
...
public void useMyMethod(Base b) {
    b.myMethod()
}

Also, you can use something similar to this

share|improve this answer
2  
You may have missed the part "How can I achieve well designed code using such type of uneditable type hierarchy ?" –  Smutje 4 hours ago
3  
Doesn't work as shown because Base does not have the required method. –  BarrySW19 4 hours ago
    
@BarrySW19, thanks! I've updated the answer. –  pbespechnyi 4 hours ago
    
I still cannot see the pattern. pbabcdefp 's answer makes it much clearer. –  5gon12eder 4 hours ago
    
@5gon12eder, I think Adapter is well-known pattern and may be easily googled. Also I added a link to Wikipedia page. –  pbespechnyi 3 hours ago

If you are using Java < 8, what about passing the function as a parameter to your useMyMethod function?

public interface A {
    void myMethod();
}

public interface B {
    void myMethod();
}

public void useMyMethod(Callable<void> myMethod) {
    myMethod.call();
}

//Use

public void test() {
    interfaceA a = new ClassImplementingA();
    useMyMethod(new Callable<void>() {
        public call() {
            a.myMethod();
        }
    });

    interfaceB b = new ClassImplementingB();
    useMyMethod(new Callable<void>() {
        public call() {
            b.myMethod();
        }
    });
}

For Java >= 8, you could use Lambda Expressions:

public interface IMyMethod {
    void myMethod();
}

public void useMyMethod(IMyMethod theMethod) {
    theMethod.myMethod();
}

//Use

public void test() {
    interfaceA a = new ClassImplementingA();
    useMyMethod(() -> a.myMethod());

    interfaceB b = new ClassImplementingB();
    useMyMethod(() -> b.myMethod());
}
share|improve this answer
1  
Not bad but it forces us to expose to the caller what methods we will invoke on the argument. Changing the implementation (simply calling another method) might force us to go and edit each use of the function. And if we want to call more than one method, it quickly becomes tedious. –  5gon12eder 3 hours ago
    
Hey @5gon12ender, your points are valid. Using an adapter has the benefit of encapsulating the call to the method, so if the method needs to be changed then only the adapter class has to be changed. On the other hand you would need to create an adapter per interface, which can become even more tedious than a functional solution. It really depends on the scope of the code (is it the internal code of a small class or a widely-used function?) and how likely to change the implementation is, I would say. –  Jorge 3 hours ago
    
I would say so too… –  5gon12eder 3 hours ago

You could write an interface MyInterface with a single method myMethod. Then, for each type you want to consider as part of the finite set, write a wrapper class, like this:

class Wrapper1 implements MyInterface {

    private final Type1 type1;

    Wrapper1(Type1 type1) {
        this.type1 = type1;
    }

    @Override
    public void myMethod() {
        type1.method1();
    }
}

Then you just need to use a MyInterface rather than one of the finite set of types, and the appropriate method from the appropriate type will always get called.

share|improve this answer
    
You may have missed the part "How can I achieve well designed code using such type of uneditable type hierarchy ?" –  Smutje 4 hours ago

Well, the correct way to model your requirement would be to have myMethod() declared in a supertype interface C which both A and B extend; your method then accepts type C as its parameter. The fact that you have trouble doing this in the situation you describe indicates you are not modelling the class hierarchy in a way that actually reflects how they behave.

Of course, if you can't change the interface structure then you could always do it with reflections.

public static void useMyMethod(Object classAorB) throws Exception {
    classAorB.getClass().getMethod("myMethod").invoke(classAorB);
}
share|improve this answer
    
To make this statically type-safe at least at the caller's site, I'd consider making the method that accepts Object private and provide public methods overloaded for each type that is to be supported. These simply delegate to the method you show. This does require a little code duplication but only technical one-liners, none of the business logic. –  5gon12eder 4 hours ago

You can try this way -

public void useMyMethod(Object obj)
    {
        if(obj instanceof A)
        {
            A a = (A)obj;
            a.myMethod();
        }
        else if(obj instanceof B)
        {
            B b = (B)obj;
            b.myMethod();
        }
    }
share|improve this answer
1  
This doesn't really solve the code duplication problem and it is anything but type-safe. –  5gon12eder 4 hours ago

The correct way is to use Java Generics.

See http://docs.oracle.com/javase/tutorial/java/generics/bounded.html

share|improve this answer
    
How would you constrain the generic type parameter to a finite set of types? –  dcastro 4 hours ago
    
Well obviously you have a base interface or object type, say type "AorB", which has a method definition or implementation. So you define a public interface Functor<T extends AorB>{}. You can multiple bound T to a series of types: <T extends B1 & B2 & B3> –  StarShine 4 hours ago
    
The OP cannot edit the existing interfaces to make them extend a common interface - "How can I achieve well designed code using such type of uneditable type hierarchy?" –  dcastro 4 hours ago
    
Well, using multiple-bound extends, it is still possible. –  StarShine 4 hours ago
1  
I don't use Java, but looking at the documentation, it seems you can force a generic type parameter to extend multiple types (T extends A & B) - but you can't force it to extend one of multiple types. –  dcastro 3 hours ago

This might not constitute a best practice, but could you make a new class (call it C), that contains the parts from A and B that are duplicated, and the make a new method that takes C, have your methods that take A and B make a C instance and call the new method?

So that you have

class C {
    // Stuff from both A and B
}

public void useMyMethod(A a) {
    // Make a C
    useMyMethod(c);
}

public void useMyMethod(B b) {
    // Make a C
    useMyMethod(c);
}

public void useMyMethod(C c) {
    // previously duplicated code
}

That would also let you keep any non duplicated code in the methods for A and B (if there is any).

share|improve this answer

This looks to me much like the template pattern:

public interface A {

    void myMethod();
}

public interface B {

    void myMethod();
}

public class C {

    private abstract class AorBCaller {

        abstract void myMethod();

    }

    public void useMyMethod(A a) {
        commonAndUseMyMethod(new AorBCaller() {

            @Override
            void myMethod() {
                a.myMethod();
            }
        });
    }

    public void useMyMethod(B b) {
        commonAndUseMyMethod(new AorBCaller() {

            @Override
            void myMethod() {
                b.myMethod();
            }
        });
    }

    private void commonAndUseMyMethod(AorBCaller aOrB) {
        // ... Loads of stuff.
        aOrB.myMethod();
        // ... Loads more stuff
    }
}

In Java 8 it is much more succinct:

public class C {

    // Expose an "A" form of the method.
    public void useMyMethod(A a) {
        commonAndUseMyMethod(() -> a.myMethod());
    }

    // And a "B" form.
    public void useMyMethod(B b) {
        commonAndUseMyMethod(() -> b.myMethod());
    }

    private void commonAndUseMyMethod(Runnable aOrB) {
        // ... Loads of stuff -- no longer duplicated.
        aOrB.run();
        // ... Loads more stuff
    }
}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.