Use Cases and Examples of GoF Decorator Pattern fo

2019-01-01 14:52发布

I have read in wikipedia that Decorator pattern is used for .Net and Java IO classes.

Can anybody explain how this is being used? And what is the benefit of it with a possible example?

There is an example of Windows forms on wikipedia but I want to know how it happens with Java IO classes.

8条回答
孤独总比滥情好
2楼-- · 2019-01-01 15:09

The decorator pattern is used in java.io classes when you manipulated input/output streams (and the same applies for readers and writers).

inputstream, bytearrayinputstream, stringbuilderinputstreams and so on are based elements. Filterinputstream is the base class for the decorator classes. Filter input streams (such as bufferedinput stream) can do additional things when they read streams or write to them.

They are built by encapsulating a stream, and are streams themselves.

new BufferedReader( new FileInputStream() ).readLine();

I can't think of any class implementing this pattern in java.net, but I think your were told about this package as it is strongly tied to java.io (socket.getInputStream for instance).

Actually, here is a course from O'Relly that explains how decorator is implemented in java.io.

Regards, Stéphane

查看更多
裙下三千臣
3楼-- · 2019-01-01 15:09

The decorator pattern is used to add functionality to existing objects such as a class defined in a library. You can then "decorate" it to fit your needs. If you are interested in learning more about patterns I recommend "Design Patterns" by the Gang of Four.

查看更多
无色无味的生活
4楼-- · 2019-01-01 15:18

A - Decorator Pattern

A.1 - Use Case of Decorator Pattern

Decorator pattern is used for extending a legacy functionality without changing the legacy class. Let's say, we have a concrete class that implements an interface. And we need to extend the functionality of the existing method however because that the existing class, and its methods are already used by other classes, thus we don't want to make a change in the existing classes. But we also need extended functionality on newer class, then how do we solve this problem?

1- We can't change the existing legacy code
2- We want to extend the functionality

So we use decorator pattern, wrap the existing class inside the decorators.

B - Basic GoF Decorator Pattern Example

Here we have a simple interface and an implementation/concrete class. The interface has one simple method, which is getMessageOfTheDay and it returns a String. Assume that there are lots of other classes using this method. So if we want to make a change in the implementation/concrete class, it will affect the old legacy code. We want to change it for only the new classes so we use the decorator pattern.

Here is a trivial example of Gang Of Four Decorator Design pattern;

B.1 - Greeter.java

public interface Greeter {
    String getMessageOfTheDay();
}

B.2 - BasicGreeter.java

public class BasicGreeter implements Greeter {

    @Override
    public String getMessageOfTheDay() {
        return "Welcome to my server";
    }

}

B.3 - Abstract Decorator Class: GreeterDecorator.java

public abstract class GreeterDecorator implements Greeter {

    protected Greeter greeter;

    public GreeterDecorator(Greeter greeter) {
        this.greeter = greeter;
    }

    public String getMessageOfTheDay() {
        return greeter.getMessageOfTheDay();
    }

}

B.4 - Concrete Decorator Class: StrangerDecorator.java

public class StrangerDecorator extends GreeterDecorator {

    public StrangerDecorator(Greeter greeter) {
        super(greeter);
    }

    @Override
    public String getMessageOfTheDay() {
        return "Hello Stranger " + super.getMessageOfTheDay();
    }

}

B.5 - Demo Code: DecoratorDemo .java

public class DecoratorDemo {

    public static void main(String[] args) {
        Greeter greeter = new BasicGreeter();

        String motd = greeter.getMessageOfTheDay();

        System.out.println(motd);

        Greeter newGreeter = new StrangerDecorator(greeter);

        String newMotd = newGreeter.getMessageOfTheDay();

        System.out.println(newMotd);

        Greeter muchNewGreeter = new StrangerDecorator(new StrangerDecorator(greeter));

        String newestMotd = muchNewGreeter.getMessageOfTheDay();

        System.out.println(newestMotd);
    }

}

Take a look at those examples. The abstract decorator class is needed to wrap the original contract and implementation. Using the abstract decorator, you can create newer multiple decorators but in this example, BasicGreeter is wrapped inside the abstract decorator and we have only created on new decorator class which is StrangeGreeter. Please notify that decorator classes can be used like a train, we can wrap a decorator inside another decorator or the same. The functionality is extendable but the original class is preserved without any modification.

C - OutputStream Demo

Let's take a look at this example. We want to write a string to file with OutputStream. Here is the demo code;

C.1 - Sample OutputStream Demo To Write A File

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class FileWriterDemo {

    public static void main(String[] args) throws IOException {
        File file = new File("./normal.txt");
        file.createNewFile();

        OutputStream oStream = new FileOutputStream(file);

        String content = "I love Commodore 64";

        oStream.write(content.getBytes());

        oStream.close();
    }

}

C.2 - JSON Decorator Output: normal.txt

There will be a new file with name "normal.txt" created under the project folder and the content will be;

I love Commodore 64

D - JSON OutputStream Decorator Demo

Now, I want to create a JSON wrapper format, which is as follows;

{
    data: <data here>
}

What I want is to write the content inside a simple one field JSON format. How can we achieve this goal? There are many trivial ways. However, I will use the GoF Decorator Pattern by writing a JSONDecorator which extends the OutputStream class of Java;

D.1 - JSON Decorator for OutputStream: JSONStream.java

public class JSONStream extends OutputStream {

    protected OutputStream outputStream;

    public JSONStream(OutputStream outputStream) {
        this.outputStream = outputStream;
    }

    @Override
    public void write(int b) throws IOException {
        outputStream.write(b);
    }

    @Override
    public void write(byte[] b) throws IOException {
        String content = new String(b);

        content = "{\r\n\tdata:\"" + content + "\"\r\n}";

        outputStream.write(content.getBytes());
    }

}

D.2 - JSON Decorator Demo: JSONDecoratorDemo.java

public class JSONDecoratorDemo {

    public static void main(String[] args) throws IOException {
        File file = new File("./json.txt");
        file.createNewFile();

        OutputStream oStream = new FileOutputStream(file);

        JSONStream js = new JSONStream(oStream);

        String content = "I love Commodore 64";

        js.write(content.getBytes());

        js.close();
        oStream.close();
    }

}

D.3 - JSON Decorator Output: json.txt

{
    data:"I love Commodore 64"
}

Actually, OutputStream itself a Decorator Pattern, it is the abstract decorator and concrete decorator in here is the JSONStream class.

查看更多
素衣白纱
5楼-- · 2019-01-01 15:18

One way you can decorate an input/output stream is to apply compression/decompression to it. See the classes in java.util.zip, for example. Such a decorated stream can be used exactly the same way as a "regular" input/output stream, with compression/decompression performed totally transparently.

查看更多
妖精总统
6楼-- · 2019-01-01 15:18

Well, I may be late to the party but this question never gets old. The key point to understand Decorator is that it gives you the ability to plug an object to an existing object to another existing object and so on. It is popular to implement this pattern in a constructor. For example,

    Icecream ic = new RainbowTopUp(new ChocoTopUp(new Vanilla()));

If you look at the diagram in the wikipedia, you would see ConcreteComponent and Decorator inherit from the same superclass/interface, Component. That is, these two classes have the same implement method(s).

However, in the Decorator class, you'd see an arrow back to the Component, which means you use Component somewhere in the Decorator class. In this case, you use the Component as a datatype of a constructor in the Decorator. That is the big trick. Without this trick, you won't be able to plug a new object to an existing object.

After that, you can create subclasses inheriting from the Decorator class. Because all classes have the same root, every single classes can freely plugin without any order.

查看更多
十年一品温如言
7楼-- · 2019-01-01 15:28

In .NET, there are a bunch of stream decorators, like BufferedStream, CryptoStream, GzipStream, etc. All those decorate Stream class.

查看更多
登录 后发表回答