intentions

Adding additional responsibilities to an object dynamically gives the Decorator pattern more flexibility in terms of adding functionality than subclassing

Alias: Wrapper

The birth of the decorator pattern

Sometimes we want to add functionality to an object rather than the entire class. For example, a GRAPHICAL user interface toolkit allows you to add features, such as borders, to any user interface component.

Using inheritance is an effective way to add functionality, but it’s not flexible because the selection of borders is static and the user has no control over how or when to add borders to components. A more flexible approach is to embed the component in another object with a border, which we call a decorator.

Speaking English is:

[Product] : Development brother, I have a piece of code here, you need to call its functions and supplement the company’s additional functions but do not touch its own content, can you do it?


[Development] : Huh? No way! How can you not change the code and need other functionality, but have additional functionality? Should I write it like this?

void demo (a) {
    // Call the original code function
    // do();
    
    // Call the company function
 // doMine(); } Copy the code

【BOSS】 : Knock big head! Don’t you think it’s low?

[development] : But not so write I how to rewrite?

[BOSS] : If you look at the original code, they all implement the same interface, which is a breakthrough point

[Development] : I go to research….

HeadFirst core code

As a result, we started reading classic books on design patterns

/ * ** Common interface for decorator patterns* /
public interface Component {
    String getName(a);
 double getSpend(a); }   / * ** The original class* / public class ConcreteComponent implements Component {   private String name;   public ConcreteComponent(String name) {  this.name = name;  }   @Override  public String getName(a) {  return name;  }   @Override  public double getSpend(a) {  return 10;  } }   / * ** The decorator class notes that it takes advantage of composition, as well as the function implementation part* / public class MilkDecorator implements Component {   Component coffe;   MilkDecorator(Component coffe) {  this.coffe = coffe;  }   @Override  public String getName(a) {  return coffe.getName() + , "milk";  }   @Override  public double getSpend(a) {  return coffe.getSpend() + 2D;  } } Copy the code

The design idea of decorator mode:

  • Component: Defines an object interface, uniform behavior, and parent
  • ConcreteComponent: Define an object to which you can add responsibilities (methods)
  • Decorator (unnecessary) : Define an interface consistent with Component and constrain the responsibilities (methods) that need to be implemented
  • ConcreteDecorator: Enhances the object’s behavior by maintaining a pointer to a Component object and implementing the Component interface

In a nutshell,

  1. We need an interface to unify the parent and specify the necessary behavior
  2. The default implementation class implements related functionality
  3. If additional additions (decorations) are needed, implement the interface and hold a pointer to the interface object, calling and enhancing the pointer object’s methods when implementing interface methods

If it seems a bit ambiguous, after reading this article, visit the Thematic Design Patterns open source project, which has specific code examples, linked at the bottom

Design principles followed

  1. “Open for extension, closed for modification” : the perfect way to enhance the method without modifying its code
  2. “Programming for interfaces” : Decorators have the same parent as themselves

What scenarios are suitable for use

Add responsibilities to a single object dynamically and transparently without affecting other objects

Code/ Practical applications in life

The best-known use of the decorator pattern in Java is the various InputStream, Reader, and Writer implementation classes in the java.io package. If we want to read text content from a file, we can use FileReader and FileInputStream;

But if we want to read faster, we need a BufferedReader, and we can do that by changing one line of code

The last

Attached is a UML diagram of the decorator pattern from GOF:

Decorator pattern UML diagram

Related code links

Making the address

  • The examples from HeadFirst and GOF are taken into account
  • Friendly reading instructions are provided