Implementacja wzorca Dekorator w Javie
Ostatnimi czasy wzorzec Dekorator przydał nam się w sytuacji, w której nie chcieliśmy …
W systemie istnieją dwie klasy (FooImpl
i BarImpl
), które zależą od siebie poprzez pole konstruktora.
interface Foo {
void execute(boolean forward);
}
class FooImpl implements Foo {
private final Bar bar;
public FooImpl(Bar bar) {
this.bar = bar;
}
public void execute(boolean forward) {
System.out.print("Foo");
if (forward) {
System.out.print(" -> ");
bar.execute(!forward);
}
}
}
interface Bar {
void execute(boolean forward);
}
class BarImpl implements Bar {
private final Foo foo;
public BarImpl(Foo foo) {
this.foo = foo;
}
public void execute(boolean forward) {
System.out.print("Bar");
if (forward) {
System.out.print(" -> ");
foo.execute(!forward);
}
}
}
Taki stan nie pozwala stworzyć obiektów tychże klas bez konieczności wprowadzenia dodatkowego obiektu pośredniczącego wywołania do poprawnie stworzonego obiektu. W języku Java funkcjonalność tą realizuje klasa java.lang.reflect.Proxy
.
Aby stworzyć takie proxy potrzebna będzie jeszcze implementacja interfejsu java.lang.reflect.InvocationHandler
, do której przekazane będą wszystkie wywołania metod obiektu proxy.
class DelegateInvocationHandler implements InvocationHandler {
private Object delegate;
public void setDelegate(Object delegate) {
this.delegate = delegate;
}
public Object invoke(Object target, Method method, Object[] args)
throws Throwable {
return method.invoke(delegate, args);
}
}
Aby zbudować obiektu obu klas najpierw przygotujemy proxy FooImpl
. Korzystając z obiektu fooProxy
możemy stworzyć obiekty klas FooImpl
i BarImpl
za pomocą operatora new
. Ostatnim etapem wymaganym do poprawnego działania proxy potrzebne jest ustawienia obiektu delegata. Po wykonaniu tych wszystkich operacji wywołania metod execute
zostaną przekazane do odpowiednich obiektów.
DelegateInvocationHandler handler = new DelegateInvocationHandler();
Foo fooProxy = (Foo) Proxy.newProxyInstance(
Foo.class.getClassLoader(),
new Class[]{Foo.class},
handler);
Bar bar = new BarImpl(fooProxy);
Foo foo = new FooImpl(bar);
handler.setDelegate(foo);
foo.execute(true); // na wyjsciu Foo -> Bar
bar.execute(true); // na wyjsciu Bar -> Foo