explanations about the Decorator design pattern

Discussion in 'Java' started by Jean Lutrin, Nov 14, 2004.

  1. Jean Lutrin

    Jean Lutrin Guest

    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
     
    Jean Lutrin, Nov 14, 2004
    #1
    1. Advertising

  2. Jean Lutrin

    xarax Guest

    "Jean Lutrin" <> wrote in message
    news:...
    > 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() ?
     
    xarax, Nov 15, 2004
    #2
    1. Advertising

  3. Jean Lutrin

    Tony Morris Guest

    "Jean Lutrin" <> wrote in message
    news:...
    > 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>

    --
    Tony Morris
    http://xdweb.net/~dibblego/
     
    Tony Morris, Nov 15, 2004
    #3
  4. Jean Lutrin

    Jean Lutrin Guest

    "xarax" <> wrote in message

    (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
     
    Jean Lutrin, Nov 15, 2004
    #4
  5. Jean Lutrin

    Jean Lutrin Guest

    Hi Tony,

    "Tony Morris" <> wrote in message news:<hlUld.36591$>...

    (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
     
    Jean Lutrin, Nov 15, 2004
    #5
  6. Jean Lutrin

    Chris Uppal Guest

    Jean Lutrin wrote:

    > 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
     
    Chris Uppal, Nov 16, 2004
    #6
  7. Jean Lutrin

    Jean Lutrin Guest

    (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
     
    Jean Lutrin, Nov 18, 2004
    #7
  8. Jean Lutrin

    Jean Lutrin Guest

    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
     
    Jean Lutrin, Nov 18, 2004
    #8
  9. Jean Lutrin

    Chris Uppal Guest

    Jean Lutrin wrote:

    > > 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 ?


    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
     
    Chris Uppal, Nov 18, 2004
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Gregory
    Replies:
    3
    Views:
    357
    Gregory
    Dec 15, 2006
  2. Chris Forone

    design q: decorator pattern

    Chris Forone, Jul 10, 2008, in forum: C++
    Replies:
    10
    Views:
    691
    James Kanze
    Jul 11, 2008
  3. Pallav singh
    Replies:
    0
    Views:
    366
    Pallav singh
    Jan 22, 2012
  4. Pallav singh
    Replies:
    0
    Views:
    405
    Pallav singh
    Jan 22, 2012
  5. Pallav singh
    Replies:
    1
    Views:
    454
    Peter Remmers
    Jan 22, 2012
Loading...

Share This Page