Object-oriented – What are the benefits of using a ‘decorator factory’ that decorates objects

decoratordesign-patternsfactoryobject-oriented

In a project I decided to implement the Decorator pattern.

I have a class Thing with methodA(), and a class AbstractDecorator that inherits from Thing and that all decorators inherit from: ConcreteDecorator1, ConcreteDecorator2, etc. All of them of course override methodA() to add some functionality before delegating to the wrapped Thing. Usual Decorator implementation.

I decided to implement a WrappingFactory (for a lack of a better name): it receives Thing objects and wraps them with a specified decorator. Some of the decorators require a parameter in the constructor, and WrappingFactory takes care of that too. Here it is:

public class WrappingFactory{

    public static void addSomeFunctionality(Thing thing){
        thing = new SomeDecorator(thing);
    }

    public static void addFunctionalityWithParameter(Thing thing, int param){
        thing = new DecoratorWithParameter(thing, param);
    }

    public static void addSomeAwesomeFunctionality(Thing thing){
        thing = new AwesomeDecorator(thing);
    }

}

I did this but actually I don't know why. Does this have benefits as opposed to having the client instantiate decorators directly?

If this has benefits, please explain them to me.

Best Answer

First, MichaelT's comments are spot-on. And there's absolutely no reason to create an AbstractDecorator class.

That said, here is an example of a "decorator factory": the factory determines, based on the input filename, whether or not to add a GZip decoder into the stack of decorated streams.

public static InputStream openFile(File file)
throws IOException
{
    InputStream stream = null;
    try
    {
        stream = new FileInputStream(file);
        stream = new BufferedInputStream(stream);
        if (file.getName().endsWith(".gz"))
            stream = new GZIPInputStream(stream);
        return stream;
    }
    catch (IOException ex)
    {
        closeQuietly(stream);
        throw ex;
    }
}

The other -- main -- reason that this factory is useful is that it properly handles cleanup in case one of the constructors fails. Which is something that (1) many programmers (myself included) won't get right if they make explicit calls, and (2) eliminates boilerplate code.