views:

117

answers:

3

I have a problem in a class of mine that uses the decorator pattern.

The problem arises when the inner object uses the "this" reference in calls to other objects. This causes all calls from the object that received the "this" reference to be made directly to the inner object, without going through the outer first.

What is the usual way to solve this problem?

Thanks.

+1  A: 

In general, you can't. Unless you subclass your decorated class, your inner class will be free to call any method using itself as parameter, and there is no way to change it.

When using the decorator pattern, the decorator class is in charge of passing the this reference (referencing the decorator itself) to other methods. From my point of view, the decorator is the most similar thing to a proxy: the inner decorated object is completely wrapped into its decorator(s) and is not directly accessible. So, you must find by yourself a way to disallow your decorated object to directly access other objects and being able to pass this reference

djechelon
+2  A: 

Objects have an implicit value: their identity (can be tested by applying ==). When you wrap them, you effectively hide that identity (worse, you also expose a potentially misleading identity, the identity of the wrapper itself). So an obvious approach is compensating for this by exposing the identity of the object via another way - explicitly. E.g. you might introduce a method Object getIdentity(), that returns an object really representing the intended identity, and allowing applying == to it.

The huge downside though is that you still allow == on the decorator itself, e.g. a hazard that:

  • is natural enough to be tricked into it (identity == decorator instead of identity == decorator.getIdentity())
  • silently does the wrong thing (compare with a runtime exception - good luck debugging that)

The problem would be non-existent if, for example, objects had a method like:

protected Object getIdentity() {
    return this;
}

On which == operator would be defined, so a wrapper could also wrap the identity of the wrapped object, instead of replacing it with its own.

Dimitris Andreou
I think this is the way I'm going to go. Adding a setIdentity and getIdentity to my base interface will make it possible to get my desired functionality.
monoceres
A: 

What you're describing is a blend of the decorator and template patterns. The decorator pattern permits you to add behavior dynamically to an object (through the use of a proxy-like mechanism). The template pattern breaks an algorithm into several methods so you can vary an object's behavior by substituting methods via subclassing, or in your case, the decorator.

Because decorators are a type of proxy, they hold a reference to the target object (or another decorator wrapped n-layers deep around the target object). But the target usually doesn't track its decorators or make any assumption regarding decorators.

So every time the target object's behavior is altered by adding or removing the outermost decorator your design will either need to update the target object with a reference to its outermost decorator or the target object will need to query another object for the outermost decorator's reference.

If the target object can query the reference to the decorated object stack from whichever object is responsible for holding it (something must), then you're probably ok. Otherwise the target object might need to resort to a delegate or mediator.

Huperniketes