Design Patterns article

The mediator pattern

The proxy pattern

Abstract Factory Pattern details – Head First design pattern

Decorator pattern

Adapter mode

The strategy pattern

Observer model

Builder Mode

Decorator mode

The Decorator Pattern allows you to add new functionality to an existing object without changing its structure. This type of design pattern is a structural pattern that acts as a wrapper around existing classes.

This pattern creates a decorator class that wraps the original class and provides additional functionality while preserving the integrity of the class method signature.

Advantages:

  • Decorator pattern is more flexible than inheritance, extending functions to objects without changing the original object, in accordance with the open closed principle. Inheritance relationships are static, and the behavior is already determined at compile time, making it difficult to control how and when behaviors are added.
  • The Decorator pattern can create a variety of behavior combinations using different decorator classes on the fly.

Disadvantages:

  • The Decorator pattern leads to the design of a large number of ConcreteDecorator classes, increasing the complexity of the system.
  • 2. For objects decorated for many times, once errors occur, troubleshooting is tedious;

The structure and realization of decoration pattern

Typically, extending a class’s functionality is implemented using inheritance. But inheritance is static, highly coupled, and the subclasses swell as the number of extensions increases. If you use composition relationships to create a wrapper object (that is, a decorator object) that wraps around the real object and provides it with additional functionality while keeping the class structure of the real object intact, this is the goal of the decorator pattern. The basic structure and implementation method are analyzed below.

1. Pattern structure

Decoration mode mainly consists of the following roles.

  1. Abstract Component Role: Defines an abstract interface to specify objects that are ready to receive additional responsibilities.
  2. Concrete Component roles: Implement abstract artifacts and add responsibilities to them by decorating roles.
  3. Decorator role: Inherits an abstract artifact and contains instances of a concrete artifact that can be subclassed to extend its functionality.
  4. The ConcreteDecorator role: Implements methods associated with abstract decorators and adds additional responsibilities to concrete component objects.

The structure diagram of decoration mode is shown in the figure below.

2. Realization of patterns

The code for decorator mode is as follows:

package decorator; public class DecoratorPattern { public static void main(String[] args) { Component p=new ConcreteComponent(); p.operation(); System.out.println("---------------------------------"); Component d=new ConcreteDecorator(p); d.operation(); } // Interface Component {public void operation(); } class ConcreteComponent implements Component {public ConcreteComponent() {system.out.println (" ConcreteComponent "); } public void operation() {system.out.println (" operation()"); Class Decorator implements Component {private Component Component; public Decorator(Component component) { this.component=component; } public void operation() { component.operation(); }} Public ConcreteDecorator extends Decorator {public ConcreteDecorator(Component Component) { super(component); } public void operation() { super.operation(); addedFunction(); } public void addedFunction() {system.out.println (" add extra function addedFunction()"); }}Copy the code

Application implementation

Decorator mode can dynamically add capabilities to existing objects. Below, I will use a simple example to demonstrate how to use decorator pattern in a program.

1. Decorator mode

Let’s say you’re looking for a girlfriend. There are many girls from different countries, such as: The United States, China, Japan, France and so on, each of them has a different personality and interests, if you need to program simulation of such a case, assume that every girl is a Java class, so there will be hundreds of thousands of classes, like this can cause the expansion of the class, and the design of extensibility is poor.

Because if we need a new girl, we need to create a new Java class, which actually violates the OCP (open for extensions, closed for modifications) principle in program development. Let’s do another design, where each personality or interest becomes a decoration that can be dynamically added to each girl.

2. Class diagram structure

Decorator pattern sample code

// Girl.java public abstract class Girl { String description = "no particular"; public String getDescription(){ return description; } } // AmericanGirl.java public class AmericanGirl extends Girl { public AmericanGirl() { description = "+American"; } } // EuropeanGirl.java public class EuropeanGirl extends Girl { public EuropeanGirl(){ description = "+European"; } } // GirlDecorator.java public abstract class GirlDecorator extends Girl { public abstract String getDescription(); } // Science.java public class Science extends GirlDecorator { private Girl girl; public Science(Girl girl){ this.girl = girl; } @Override public String getDescription() { return this.girl.getDescription() + "+Like Science"; } public void caltulateStuff() { System.out.println("scientific calculation!" ); } } // Art.java public class Art extends GirlDecorator { private Girl girl; public Art(Girl girl){ this.girl = girl; } @Override public String getDescription() { return this.girl.getDescription() + "+Like Art"; } public void draw() { System.out.println("draw pictures!" ); }} // main.java public class Main {public static void Main (String[] args) {// Girl g1 = new AmericanGirl(); System.out.println(g1.getDescription()); // Like Science g2 = new Science(g1); System.out.println(g2.getDescription()); G3 = new Art(g2); System.out.println(g3.getDescription()); }}Copy the code

Application scenarios

The structure and characteristics of decoration mode have been explained before. The application scenarios of decoration mode are introduced below. Decoration mode is usually used in the following situations.

  • When additional responsibilities need to be added to an existing class that cannot be extended by subclassing. For example, if the class is hidden or the class is the ultimate class or inherits a large number of subclasses.
  • Inheritance is difficult to implement when you need to produce a lot of functionality by permutations of an existing set of basic functionality, and decoration is good.
  • When the functional requirements of an object can be dynamically added or removed.

The most famous use of decorator patterns in the Java language is the design of the Java I/O standard library. For example, InputStream subclass FilterInputStream, OutputStream subclass FilterOutputStream, Reader subclass BufferedReader and FilterReader, There are subclasses of Writer, BufferedWriter, FilterWriter, PrintWriter, etc., which are abstract decorator classes.

Decorator pattern applied I/O in the JDK

  • InputStream is the equivalent of the Decorator pattern Component
  • FileInputStream, ByteArrayInputStream, ObjectInputStream these objects inherit InputStream directly, equivalent to ConcreteComponent in decorator mode
  • FilterInputStream inherits InputStream and holds an InputStream, which is equivalent to a Decorator in Decorator mode
  • BufferedInputStream, PushbackInputStream, LineNumberInputStream, DataInputStream inherits FilterInputStream, Equivalent to ConcreteDecorator in decorator pattern
// Where FileInputStream equals component object, BufferedInputStream decorates the FileInputStream object. BufferedInputStream bis = New BufferedInputStream(New FileInputStream(new)  File("fileName"))); byte[] buff = new byte[1024]; bis.read(buff); System.out.println(new String(buff));Copy the code

 

Refer to the article

This is the most accessible explanation of decorator patterns I’ve ever seen!

Decorator Pattern Decorator Pattern

Detailed explanation of decoration mode (decoration design mode)