Reputation: 13588
I have an interface which has only one method. I have a static function which receives objects (these objects implement the interface), and I want to override/replace implementation of the method, that is defined in the interface, in objects. What is the best way to do this in Java
public class MyClass {
public interface MyInterface {
Object myMethod (Object blah);
}
public static MyInterface decorator(MyInterface obj) {
//I want to return a version of obj
//with a different implementation of myMethod
//everything else in obj should be same, except myMethod
}
}
Upvotes: 3
Views: 1897
Reputation: 11909
You are looking for a dynamic proxy if we can restrict it to interfaces (any number of them).
So your problem: If you call the method in that interface first without calling the decorator and then with the decorator you want different behavior, so given this interface implementation:
MyInterface o = new MyInterface() {
public Object myMethod(Object blah) {
return "bar";
}
};
This should do different things, for example alter the return value (and/or something else):
System.out.println(o.myMethod(null));
o = decorator(o);
System.out.println(o.myMethod(null));
Output:
bar
foo
This can be done with a dynamic proxy in java:
public static MyInterface decorator(final MyInterface obj) {
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("myMethod")) {
//do something special
return "foo";
}
return method.invoke(obj, args);
}
};
MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
MyInterface.class.getClassLoader(),
obj.getClass().getInterfaces(), //all or limit it to just one or a few
handler);
return proxy;
}
Update: If you want to involve more interfaces (updated proxy instance code above to get the interfaces implemented instead of hard coding it):
Now makes this work:
public static void main(String[] args) {
A o = new A();
System.out.println(o.myMethod(null));
System.out.println(o.myOtherMethod(1));
Object o2 = decorator(o);
System.out.println(((MyInterface) o2).myMethod(null));
System.out.println(((MyInterface2) o2).myOtherMethod(1));
}
With output:
bar
2
foo <-- changed
2 <- the same behavior
Given:
class A implements MyInterface, MyInterface2 {
@Override
public Object myMethod(Object blah) {
return "bar";
}
@Override
public int myOtherMethod(int a) {
return a+1;
}
}
Upvotes: 0
Reputation: 43728
Such kind of dynamic behavior is not directly supported in Java. But you can achieve something like this when the object cooperates. I.e. it could provide a method to change the implementation of myMethod
:
void changeMethod(MyInterface other) {
realImpl = other;
}
Object myMethod (Object obj) {
return realImpl.myMethod(obj);
}
Upvotes: 1
Reputation: 41200
Using CGLib you can implements interfaces at runtime.
Example -
public class KeySample {
private interface MyFactory {
public Object newInstance(int a, char[] b, String d);
}
public static void main(String[] args) {
MyFactory f = (MyFactory)KeyFactory.create(MyFactory.class);
Object key1 = f.newInstance(20, new char[]{ 'a', 'b' }, "hello");
Object key2 = f.newInstance(20, new char[]{ 'a', 'b' }, "hello");
Object key3 = f.newInstance(20, new char[]{ 'a', '_' }, "hello");
System.out.println(key1.equals(key2));
System.out.println(key2.equals(key3));
}
}
Upvotes: 0
Reputation: 200138
You can't do that generally, without the knowledge of the exact object type you are decorating. If you know it, then you can create a subclass of that particular class with the implementation changed. Java's type system just isn't flexible enough to mix and match interface implementation like you need.
You could resort to dynamic class definition techniques, which would create a dynamic proxy for every object you pass into your decorate
method, but there's an order of magnitude more complexity in such an approach.
Upvotes: 1
Reputation: 11120
You can create a class with the same interface that delegates all the methods calls yo your object, then you create an anonymous class extending it and override whatever you want
Intercace:
Interface MyInterface {
void m1();
void m2();
}
Delegating class:
class MyDelegate implements MyInterface {
private MyInterface delegate;
MyDelegate(MyInterface delegate) {
this.delegate = delegate;
}
void m1() {
delegate.m1();
}
void m2() {
delegate.m2();
}
}
In the static method you create an instance of an anonymous class extending MyDelegate
and override whatever you want, the rest will be run by obj
static MyInterface wrap(MyInterface obj) {
return new MyDelegate(obj) {
void m1() {
// overrided m1
}
// my will eventually get to obj
};
}
Upvotes: 2