explanations about the Decorator design pattern

J

Jean Lutrin

Hi all,

I have two questions: one regarding a pattern
that I don't know the name of and one other
regarding the decorator pattern.

In one project I've been working on, I had to optimize
a *very* memory consuming code (which I didn't write).

The code (oversimplified) looks like this :

abstract class SomeClass {
abstract int doSomeTask();
abstract int doAnotherTask();
abstract int doAThirdTask();
}

class Inefficient extends SomeClass {
int doSomeTask() {
// very ineficient method consuming lots of ressources
}

int doAnotherTask() {
...
}

int doAThirdTask() {
...
}
}

Once we noticed there were problems in the code, we
ran a profiler and noticed an excessive memory usage
traced back to one single method.

We had no access to the source code, so I did the
following.

I added an "optimized method" class looking like this :

class Efficient extends SomeClass {
private Inefficient wrapped;

Efficient() {
wrapped = new Inefficient();
}

int doSomeTask() {
// optimized method
};

int doSomeOtherTask() {
return wrapped.doSomeOtherTask();
}

int doAThirdTask() {
return wrapped.doSomeOtherTask();
}
}

Note that I extend SomeClass and not the Inefficient class. This
way, the client of this class only see that the class they use
extends SomeClass : they don't need to know that Efficient
actually "wrap" an Inefficient object. The inefficient method
of the Inefficient class is never called : it has been "replaced" by
another method, much more optimized. For all the rest, it is
the old class that actually does all the job.

Everything is working all and well (and "non-garbage-collectable"
memory usage went way down btw, by a factor of 60 !, which was
actually the whole purpose of this manipulation).

However, I don't know if there's a name for this way
of proceeding. I don't add any new functionality to
the class: it is a concrete implementation of the
abstract class. And this implementation is based, under
the hood, on another concrete implementation of the
abstract class (but nobody notices it: this detail is
hidden from the client). Nothing is added, no new
functionality is added.

How would you name this way of proceeding ?

Is it similar to some well known pattern ?


My second question concerns the Decorator pattern. The
Java I/O streams are often cited, nearly everywhere, as
*the* major use of the Decorator pattern in the Java API

Let's look at those three :

public abstract class InputStream {...}

public class FilterInputStream extends InputStream {...}

public class BufferedInputStream extends FilterInputStream {...}

Which class is said to be decorating which one ?

In a post from the year 2000, on this very group, I found
the following :
A classic example in Java is the FilterInputStream
class (and its many subclasses BufferedInputStream,
DataInputStream, CheckedInputStream, InflaterInputStream,
DigestInputStream, LineNumberInputStream, PushbackInputStream)
which is a Decorator of an InputStream. It provides the same
API as the InputStream which it wraps, but allows you to
add additional capability. It is this idea of adding
functionality by wrapping another object while implementing
the same API that is characteristic of the Decorator pattern.

I too, think Decorator is an extremely poor name.

I would be tempted to say "of course that the FilterInputStream
has the same interface as the InputStream"... The InputStream
is an abstract class !

So Does it means that everytime you extends an abstract class
(without making the extending class final) you are using
the "Decorator" pattern ?

I don't see which object is wrapping which one : do you
really find that the FilterInputStream wraps the
abstract InputStream class ?

Thanks in advance for any help on this.

As always, excuse my french ;)

Jean
 
X

xarax

Jean Lutrin said:
Hi all,

I have two questions: one regarding a pattern
that I don't know the name of and one other
regarding the decorator pattern.

In one project I've been working on, I had to optimize
a *very* memory consuming code (which I didn't write).

The code (oversimplified) looks like this :

abstract class SomeClass {
abstract int doSomeTask();
abstract int doAnotherTask();
abstract int doAThirdTask();
}

class Inefficient extends SomeClass {
int doSomeTask() {
// very ineficient method consuming lots of ressources
}

int doAnotherTask() {
...
}

int doAThirdTask() {
...
}
}

Once we noticed there were problems in the code, we
ran a profiler and noticed an excessive memory usage
traced back to one single method.

We had no access to the source code, so I did the
following.

I added an "optimized method" class looking like this :

class Efficient extends SomeClass {
private Inefficient wrapped;

Efficient() {
wrapped = new Inefficient();
}

int doSomeTask() {
// optimized method
};

int doSomeOtherTask() {
return wrapped.doSomeOtherTask();
}

int doAThirdTask() {
return wrapped.doSomeOtherTask();
}
}

Note that I extend SomeClass and not the Inefficient class. This
way, the client of this class only see that the class they use
extends SomeClass : they don't need to know that Efficient
actually "wrap" an Inefficient object. The inefficient method
of the Inefficient class is never called : it has been "replaced" by
another method, much more optimized. For all the rest, it is
the old class that actually does all the job.
/snip/

What's wrong with just extending Inefficient and
overriding doSomeTask() ?
 
T

Tony Morris

Jean Lutrin said:
Hi all,

I have two questions: one regarding a pattern
that I don't know the name of and one other
regarding the decorator pattern.

In one project I've been working on, I had to optimize
a *very* memory consuming code (which I didn't write).

The code (oversimplified) looks like this :

abstract class SomeClass {
abstract int doSomeTask();
abstract int doAnotherTask();
abstract int doAThirdTask();
}

class Inefficient extends SomeClass {
int doSomeTask() {
// very ineficient method consuming lots of ressources
}

int doAnotherTask() {
...
}

int doAThirdTask() {
...
}
}

Once we noticed there were problems in the code, we
ran a profiler and noticed an excessive memory usage
traced back to one single method.

What you have there is the Proxy Design Pattern.
I'd be inclined to call it the Adapter Design Pattern, but the two share the
same API.
I have sincere doubts that this is the cause of a performance bottleneck.

The Decorator Design Pattern is similar to a Proxy, however, there is one
distinguishing feature.
The type (typically an interface) being subtyped (always a class) has a
member of the type being subtyped.
For example a class called XDecorator which decorated the type interface X
looks like this:

class XDecorator implements X
{
private X x;

... // all of X methods
}

The methods that you provide 'decorate' the behaviour of the instance of X
that the member field refers to.
Typically, this instance is passed in on the constructor.
The UML for a Decorator includes two types, the decorating type and the
decorated type.
There is an inheritance relationship as the decorating type being a subtype
of the decorated type.
There is also an aggregation relationship from the decorating type to the
decorated type.

In the case of core I/O, the two abstract classes java.io.InputStream and
java.io_OutputStream are the decorated type.
The many (not all) concrete implementations are decorating types.
Consider java.io_ObjectInputStream.
It inherits from java.io.InputStream and you also pass a java.io.InputStream
in at construction time.
ObjectInputStream 'decorates' the InputStream that you provide it with.

AOP solves a lot of the same problems, but in a different way, that a
decorator solves.

</essay>
 
J

Jean Lutrin

(snip)
What's wrong with just extending Inefficient and
overriding doSomeTask() ?

Hi Xarax,

I could have done it, and that's why I precised that
I decided not too. But I didn't explain why.

First reason is that I prefer to use the higher
abstraction as possible. As Tony Morris pointed out, the
method I employed is very similar to (if not exactly) a
Proxy and:

"Classes for proxy objects are declared in a way that usually
eliminates client object's awareness that they are dealing
with a proxy."

I made this choice by myself though, because it somehow
felt, to me, the right thing to do.

The second reason is that, in my particular case, it looks
like this (oversimplified and class names changed to
protect the innocent ;) :


abstract class Solver {...}

class SlowSolver extends Solver {...}

class FastSolver extends Solver {...}



It would feel really strange, in this code, to have
a FastSolver extends a SlowSolver.

As a little plus, if I decide one day to completely rewrite
all the methods, I can just remove the private, enclosed,
inefficient object and delete the inefficient class, without
the code requiring any other modification.

The object is really, in this example, a Solver, not a
SlowSolver: the fact that it internally uses a SlowSolver
is, to me, an implementation detail.

I don't know if it makes any sense though !?

See you soon on cljp,

Jean
 
J

Jean Lutrin

Hi Tony,


(snip)
I have sincere doubts that this is the cause of
a performance bottleneck.

Oops, sorry for my french. I didn't explain myself
correctly :(

This design choice is not the bottleneck: the bottleneck
was there before I started using the Proxy: it was
coming from a very computational (and memory) intensive
method. So I decided to find a workaround: behing able to
optimize this method, without having to re-implement all
the other methods from the class.

It looks indeed like a Proxy :)

But the Proxy design pattern is so fundamental (pun intended ;)
that I missed it !

Thanks again, and thanks for your explanations about the
Decorator. Everything is much clearer now.


Jean
 
C

Chris Uppal

Jean said:
Note that I extend SomeClass and not the Inefficient class. This
way, the client of this class only see that the class they use
extends SomeClass : they don't need to know that Efficient
actually "wrap" an Inefficient object. The inefficient method
of the Inefficient class is never called : it has been "replaced" by
another method, much more optimized. For all the rest, it is
the old class that actually does all the job.

Everything is working all and well (and "non-garbage-collectable"
memory usage went way down btw, by a factor of 60 !, which was
actually the whole purpose of this manipulation).

However, I don't know if there's a name for this way
of proceeding.

I think it's generally called "hacking it" ;-)

I'm not implying any criticism -- your solutions sounds well thought-out and
well applied. But it is still best thought of as a "hack", I would say. A
design that is very specific to this /particular/ circumstance, and which, by
/not/ following commonly occuring patterns, is able to satisfy its design goals
whilst minimising changes or other bad effects to the rest of the system.

Still, it could be described as an application of wrapping[*] and Delegation.
You class accepts the contract implied by its superclass, but actually
/implements/ the required behaviour by delagating most of it to another object.

I suppose if I were discussing this design with a collegue, I might say
something like "OK, we'll hack it by wrapping each Inefficient in a new
SomeClass object which delegates everthing /except/ doSomeTask() to that".

([*] "wrapping" is not a standard Pattern Name, but is just the word that most
people use for when one object is "hidden" inside another which controls or
modifies its behaviour -- there's some overlap with the Decorator pattern)

My second question concerns the Decorator pattern. The
Java I/O streams are often cited, nearly everywhere, as
*the* major use of the Decorator pattern in the Java API
[...]
So Does it means that everytime you extends an abstract class
(without making the extending class final) you are using
the "Decorator" pattern ?

No, definitely not.

I don't see which object is wrapping which one : do you
really find that the FilterInputStream wraps the
abstract InputStream class ?

No, the Decorator pattern (and wrapping in general) is a relation between
/objects/ not between /classes/. In fact it can be thought of as a way to
/avoid/ having (potentially very complicated) relationships between classes.
An /instance/ of FilterInputStream wraps another object which is an instance of
some kind of AbstractInputStream.

Imagine you have an abstract class "AbstractStream" -- or it might be better to
think of it as an interface -- and a concrete class "Stream" than implements
that interface.

Now, if you want to create a new kind of stream that has buffering, one of your
options would be create a subclass of Stream, "BufferedStream" that added
buffering to its parent class's behaviour. It would probably add more methods
too, extending the parent's behaviour with things like flush(). Next, imagine
that, you need a kind of stream that counts how many bytes are written to it.
Again you could use subclassing, so you'd add another class,
"CountingBufferedStream" (and perhaps "CountingStream" too) -- and already it's
getting way too complicated.

That's what the Decorator avoids -- instead of creating objects with extended
behaviour by using subclassing, it does it by composing objects at runtime, and
allowing them to extend each others' behaviours dynamically.

Instead of having /one/ object, of class CountingBufferedStream, which is also
a BufferedStream, and also a Stream, it would have /three/ objects. A
"CountingStream" which wraps a second object that is a "BufferedStream" which
in turn wraps a "Stream". If you write a byte to the outermost object (the
CountingStream) then it increments its count, and delegates (or "forwards")
writing that byte to the BufferedStream. The BufferedStream would add the byte
to the buffer, and when the buffer was full would delegate to its wrapped
Stream. It's that /dynamic/ relationship between objects, wrapping and
forwarding to each other, that is essence of Decorator. Well, it's half of it
anyway...

The other half, and what makes Decorator more than just simple wrapping and
delegation, is that the objects don't "know" what kind of AbstractStream they
wrap -- all they know about it is that it is some kind of AbstractStream, but
they don't care which concrete subclass it is. That's what gives Decorator its
flexibility. Since each Decorator object only knows that the object it wraps
(and Decorates) is an instance of a shared abstract superclass (or interface),
they can be linked together in arbitrary chains.

So, in Decorator, you have an interface (or shared abstract superclass) that
defines what the objects need /from each other/ in order to be linked together.
And you have a number of concrete subclasses, some of which have instances that
go at the end of the chains, and others with instances that wrap other
instances of the superclass. Most of the concrete subclasses will have a
public APIs that extend the superclass one in some way (e.g. to flush a buffer,
to retrieve the character count), but the point is that they don't use the
extended API to talk to each other, but only use the operations defined by the
superclass.

-- chris
 
J

Jean Lutrin

(snip)
I suppose if I were discussing this design with a collegue, I might say
something like "OK, we'll hack it by wrapping each Inefficient in a new
SomeClass object which delegates everthing /except/ doSomeTask() to that".

I've changed the docs in the class to use your sentence (almost), makes
sense.

:)


([*] "wrapping" is not a standard Pattern Name, but is just the word that most
people use for when one object is "hidden" inside another which controls or
modifies its behaviour -- there's some overlap with the Decorator pattern)

Yup, I noticed about the name "Wrapper" being often mentionned when people
talk about the Decorator pattern.


Thanks a lot for the detailed explanations about the Decorator
pattern, which I find much cleaner and in-depth than most I've found
about this pattern. (I need examples, I "understand" code when I see
examples, so your post was very helpful!).

See you soon on cljp,

Jean
 
J

Jean Lutrin

I'm on my way to understanding how the Decorator works (well, at
least I hope so)...

(snip)
Instead of having /one/ object, of class CountingBufferedStream,
which is also a BufferedStream, and also a Stream, it would
have /three/ objects. A "CountingStream" which wraps a second
object that is a "BufferedStream" which in turn wraps a "Stream".

And of course, if we wanted, there could be only two objects. Say, if
we don't need the buffering option (in this example), the
"CountingStream" could wrap directly the "Stream" !?

Which in, in some way, is what makes this pattern really great ?

Thanks a lot,

Jean
 
C

Chris Uppal

Jean said:
And of course, if we wanted, there could be only two objects. Say, if
we don't need the buffering option (in this example), the
"CountingStream" could wrap directly the "Stream" !?

Which in, in some way, is what makes this pattern really great ?

Exactly !

(Though I should add that any particular application of the Decorator pattern
may add constraints to what can be wrapped around what. Or there may be
combinations that work well and others that don't. For instance in the Java IO
streams, if you use buffering at all, then the buffered stream should normally
be wrapped immedately around the underling file stream (or whatever), and other
decorators should be wrapped around that -- just for efficiency)

-- chris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,996
Messages
2,570,238
Members
46,826
Latest member
robinsontor

Latest Threads

Top