Comparison of 8 structural design patterns

1. Adapter mode

Introduction

Adapter pattern is a structural design pattern that is used to convert incompatible interfaces into compatible interfaces. The Adapter pattern allows two incompatible classes to work together by converting the interface of one class into the interface form expected by the other class. This enables two incompatible classes to cooperate with each other without modifying existing code.

scenes to be used

The adapter pattern is usually used in the following scenarios:

  • The Adapter pattern can be used when you need to convert the interface of an existing class to another interface.
  • The Adapter pattern is a very useful tool when you need to adapt one or more existing classes to achieve a specific functionality.

Code examples

// 目标接口
interface Target {
    
    
    void request();
}

// 需要适配的类
class Adaptee {
    
    
    void specificRequest() {
    
    
        System.out.println("Adaptee's specific request");
    }
}

// 适配器类
class Adapter implements Target {
    
    
    private Adaptee adaptee;

    Adapter(Adaptee adaptee) {
    
    
        this.adaptee = adaptee;
    }

    @Override
    public void request() {
    
    
        adaptee.specificRequest();
    }
}

// 使用适配器
public class Main {
    
    
    public static void main(String[] args) {
    
    
        Adaptee adaptee = new Adaptee();
        Target target = new Adapter(adaptee);
        target.request();
    }
}

advantage

  • The adapter pattern allows two incompatible interfaces to work together, improving code reusability and flexibility.
  • The adapter pattern can decouple client code from concrete classes, reducing the client code's dependence on concrete classes.

shortcoming

  • The adapter pattern may require the creation of more classes to implement the relationship between the adapter and the adapter, increasing the complexity of the code.
  • The adapter mode may introduce a certain performance loss because the interface conversion needs to be implemented through the adapter.

Compare other models

  • The adapter pattern is similar to the bridge pattern, but the adapter pattern deals with interface conversion, while the bridge pattern deals with the separation of abstraction and implementation.
  • The adapter pattern is similar to the decorator pattern, but the adapter pattern is used for interface conversion, while the decorator pattern is used to dynamically add additional functionality to an object.

2. Bridge mode

Introduction

Bridge pattern is a structural design pattern that separates the abstract part and the implementation part so that they can change independently. By separating abstraction and implementation, the bridge pattern enables both to be extended independently. The core goal of this pattern is to decouple abstraction and implementation so that they can change independently of each other.

scenes to be used

Bridge mode is usually used in the following scenarios:

  • The bridge pattern can be used when the abstraction and implementation need to be able to change independently.
  • The bridge pattern can be used when multiple inheritance needs to be avoided.
  • When you need to change the implementation of a class without affecting other classes that use the class, you can use the bridge mode.

Code examples

// 实现部分接口
interface Implementor {
    
    
    void operationImp();
}

// 具体实现部分A
class ConcreteImplementorA implements Implementor {
    
    
    @Override
    public void operationImp() {
    
    
        System.out.println("ConcreteImplementorA operationImp");
    }
}

// 具体实现部分B
class ConcreteImplementorB implements Implementor {
    
    
    @Override
    public void operationImp() {
    
    
        System.out.println("ConcreteImplementorB operationImp");
    }
}

// 抽象部分接口
abstract class Abstraction {
    
    
    protected Implementor implementor;

    Abstraction(Implementor implementor) {
    
    
        this.implementor = implementor;
    }

    abstract void operation();
}

// 具体抽象部分
class ConcreteAbstraction extends Abstraction {
    
    
    ConcreteAbstraction(Implementor implementor) {
    
    
        super(implementor);
    }

    @Override
    void operation() {
    
    
        implementor.operationImp();
    }
}

// 使用桥接模式
public class Main {
    
    
    public static void main(String[] args) {
    
    
        Implementor implementorA = new ConcreteImplementorA();
        Implementor implementorB = new ConcreteImplementorB();

        Abstraction abstractionA = new ConcreteAbstraction(implementorA);
        abstractionA.operation();

        Abstraction abstractionB = new ConcreteAbstraction(implementorB);
        abstractionB.operation();
    }
}

advantage

  • The bridge mode enables the abstract part and the implementation part to change independently, decoupling the abstraction and implementation, and improving the flexibility and scalability of the code.
  • Bridge mode can dynamically switch implementations at runtime without modifying client code.

shortcoming

  • The bridge pattern may increase the complexity of the system because additional abstraction and implementation classes need to be created to bridge.
  • The bridge pattern may increase the overhead of the system because the separation of abstraction and implementation is required through the bridge.

Compare other models

  • The Bridge pattern is similar to the Adapter pattern, but the Bridge pattern is used to handle the separation of abstraction and implementation, while the Adapter pattern is used to handle interface conversion.
  • The bridge pattern is similar to the decorator pattern, but the bridge pattern is used to separate abstraction and implementation, while the decorator pattern is used to dynamically add additional functionality to an object.

3. Combination mode

Introduction

The Composite pattern is a structural design pattern that allows objects to be combined into a tree structure to represent a whole-part hierarchy. By using the composition pattern, you can work with combinations of objects and individual objects in a unified manner.

scenes to be used

  • When you want to organize objects in a tree structure, you can use the combination pattern. For example, files and directories in a file system can be represented using a composite pattern, where each directory can contain subdirectories and files.
  • When you need to process the entire collection of objects or a part of them, you can use the composition pattern. For example, calculating the total salary of all employees in a department can be calculated by traversing the department's tree structure.

Code examples

// 抽象组件
interface Component {
    
    
    void operation();
}

// 叶子组件
class Leaf implements Component {
    
    
    public void operation() {
    
    
        System.out.println("Leaf operation");
    }
}

// 复合组件
class Composite implements Component {
    
    
    private List<Component> components = new ArrayList<>();

    public void add(Component component) {
    
    
        components.add(component);
    }

    public void remove(Component component) {
    
    
        components.remove(component);
    }

    public void operation() {
    
    
        System.out.println("Composite operation");
        for (Component component : components) {
    
    
            component.operation();
        }
    }
}

// 使用示例
public class Main {
    
    
    public static void main(String[] args) {
    
    
        Component leaf1 = new Leaf();
        Component leaf2 = new Leaf();
        Component composite1 = new Composite();
        Component composite2 = new Composite();
        composite1.add(leaf1);
        composite1.add(leaf2);
        composite2.add(composite1);
        composite2.operation();
    }
}

Advantages and Disadvantages

advantage:

  • The client code can be simplified, and the client can handle composite objects and leaf objects uniformly.
  • It is easy to add or remove components, and the client does not need to care about the specific component type.

shortcoming:

  • It increases the complexity of the system and may increase the code maintenance burden in some cases.
  • When using the composition pattern, there is a trade-off between transparency and security, which can lead to ambiguous designs.

Compare with other modes

  • Composition pattern and decorator pattern: Both involve object composition, but the decorator pattern focuses on dynamically adding functions to objects, while the composition pattern focuses on tree structures.
  • Composite pattern and Bridge pattern: Both involve object composition, but Bridge pattern focuses on decoupling abstraction and implementation, while Composite pattern focuses on tree structure.
  • Combination mode and flyweight mode: Both involve object sharing, but the combination mode focuses on the tree structure and shares the whole, while the flyweight mode focuses on the sharing of fine-grained objects.

4. Decorator mode

Introduction

The Decorator pattern is a structural design pattern that allows you to dynamically add additional functionality to an object. The decorator pattern wraps the original object with an additional object and performs additional operations before and after calling the original object's methods.

scenes to be used

  • When you need to dynamically add additional functionality or behavior to an object, you can use the decorator pattern. For example, to cache database query results at runtime, you can use the decorator pattern to wrap the query operation.
  • The decorator pattern can be used when you want more flexibility in inheritance relationships. The decorator pattern allows you to dynamically add additional functionality to an object, avoiding the limitations of static inheritance.

Code examples

# 抽象组件
class Component:
    def operation(self):
        pass

# 具体组件
class ConcreteComponent(Component):
    def operation(self):
        print("ConcreteComponent operation")

# 装饰器基类
class Decorator(Component):
    def __init__(self, component):
        self._component = component

    def operation(self):
        self._component.operation()

# 具体装饰器
class ConcreteDecoratorA(Decorator):
    def operation(self):
        super().operation()
        print("ConcreteDecoratorA operation")

class ConcreteDecoratorB(Decorator):
    def operation(self):
        print("ConcreteDecoratorB operation")
        super().operation()

# 使用示例
component = ConcreteComponent()
decoratorA = ConcreteDecoratorA(component)
decoratorB = ConcreteDecoratorB(decoratorA)
decoratorB.operation()

Advantages and Disadvantages

advantage:

  • Additional functionality can be added dynamically to an object without modifying the original object's code.
  • The decorator pattern follows the opening and closing principle, allowing you to add new functionality to an object without modifying existing code.

shortcoming:

  • It increases the complexity of the system, and it is necessary to avoid excessive nesting of decorators.
  • You need to pay attention to the order of decorators, because the order in which decorators are executed may affect the final result.

Compare with other modes

  • Decorator pattern and proxy pattern: Both involve object packaging, but the decorator pattern focuses on dynamically adding functionality, while the proxy pattern focuses on controlling access to objects.
  • Decorator pattern and adapter pattern: Both involve the packaging of objects, but the adapter pattern focuses on adapting objects with different interfaces into a unified interface, while the decorator pattern focuses on dynamically adding functionality.
  • Decorator pattern and bridge pattern: Both involve the packaging of objects, but the decorator pattern focuses on dynamically adding functionality to the object, while the bridge pattern focuses on decoupling the abstract part and the implementation part.

5. Appearance mode

Introduction

Facade pattern is a structural design pattern that provides a unified interface for accessing a set of interfaces of a subsystem. The facade pattern simplifies the interaction between the client and the subsystem by encapsulating a complex set of subsystem interfaces.

scenes to be used

  • When you want to simplify a complex subsystem and provide a unified interface, you can use the facade pattern. For example, when the client needs to interact with multiple components such as databases, caches, message queues, etc., these interactions can be encapsulated through appearance patterns and provide a unified interface to the outside world.
  • The facade pattern can be used when you need to decouple dependencies between clients and subsystems.

Code examples

# 子系统A
class SubsystemA:
    def methodA(self):
        print("SubsystemA methodA")

# 子系统B
class SubsystemB:
    def methodB(self):
        print("SubsystemB methodB")

# 外观类
class Facade:
    def __init__(self):
        self._subsystemA = SubsystemA()
        self._subsystemB = SubsystemB()

    def operation(self):
        self._subsystemA.methodA()
        self._subsystemB.methodB()

# 使用示例
facade = Facade()
facade.operation()

Advantages and Disadvantages

advantage:

  • The interaction between the client and the subsystem is simplified. The client only needs to interact with the appearance class and does not need to know the details of the subsystem.
  • Decoupling the dependency relationship between the client and the subsystem, the client only needs to rely on the appearance class.

shortcoming:

  • Too much reliance on appearance classes may lead to a decrease in system maintainability and is not conducive to system expansion.

Compare with other modes

  • Appearance mode and adapter mode: Both involve encapsulation, but appearance mode focuses on the unified encapsulation of a set of interfaces, while adapter mode focuses on the adaptation of different interfaces.
  • Facade pattern and Mediator pattern: Both involve decoupling client and subsystem dependencies, but Mediator pattern focuses on interaction through mediating objects, while Facade pattern focuses on providing a unified interface.
  • Facade pattern and proxy pattern: Both involve encapsulation, but the proxy pattern focuses on controlling access to objects, while the facade pattern focuses on the unified encapsulation of a set of interfaces.

6. Flying Dollar Mode

Introduction

Flyweight pattern is a structural design pattern that reduces memory usage by sharing objects to support a large number of fine-grained objects. Flyweight mode divides the object's state into internal state and external state. The internal state can be shared and the external state can be passed in by the client.

scenes to be used

  • Flyweight pattern can be used when a large number of fine-grained objects need to be created and the internal state can be shared. For example, letter objects in a web page editor can be shared through flyweight mode.
  • Flyweight pattern can be used when most of the state of the object can be passed in from the outside and does not depend on the specific object.

Code examples

import java.util.HashMap;
import java.util.Map;

// 具体享元类
class ConcreteFlyweight implements Flyweight {
    
    
    private String intrinsicState;

    public ConcreteFlyweight(String intrinsicState) {
    
    
        this.intrinsicState = intrinsicState;
    }

    public void operation(String extrinsicState) {
    
    
        System.out.println("Intrinsic state: " + intrinsicState);
        System.out.println("Extrinsic state: " + extrinsicState);
    }
}

// 享元工厂
class FlyweightFactory {
    
    
    private Map<String, Flyweight> flyweights = new HashMap<>();

    public Flyweight getFlyweight(String key) {
    
    
        if (!flyweights.containsKey(key)) {
    
    
            flyweights.put(key, new ConcreteFlyweight(key));
        }
        return flyweights.get(key);
    }
}

// 使用示例
public class Main {
    
    
    public static void main(String[] args) {
    
    
        FlyweightFactory factory = new FlyweightFactory();
        Flyweight flyweight1 = factory.getFlyweight("key1");
        flyweight1.operation("state1");
        Flyweight flyweight2 = factory.getFlyweight("key2");
        flyweight2.operation("state2");
    }
}

Advantages and Disadvantages

advantage:

  • It can reduce memory usage and improve system performance.
  • In scenarios with large-scale fine-grained objects, a lot of memory space can be saved.

shortcoming:

  • It increases the complexity of the system, requires management of external state, and may introduce thread safety issues.
  • There is a trade-off between the degree of sharing between internal and external state.

Compare with other modes

  • Flyweight pattern and singleton pattern: Both involve shared objects, but the singleton pattern focuses on single instances, while the flyweight pattern focuses on sharing fine-grained objects.
  • Flyweight pattern and prototype pattern: Both involve creating objects, but prototype pattern focuses on cloning objects, while flyweight pattern focuses on shared objects.
  • Flyweight mode and proxy mode: Both involve the encapsulation of objects, but the proxy mode focuses on controlling access to objects, while the flyweight mode focuses on the internal state of shared objects.

7. Agency model

Introduction

Proxy pattern is a structural design pattern used to control access to objects and add additional processing when accessing objects. The proxy mode replaces the original object by creating a proxy object. The client uses the proxy object to perform operations. The proxy object can add some additional logic before and after performing operations.

scenes to be used

  • When you need to control access to objects, you can use the proxy pattern. For example, to restrict access to sensitive data, you can create a proxy object to authenticate before accessing sensitive data.
  • The proxy pattern can be used when additional processing logic needs to be added when accessing an object. For example, operations such as logging and caching results can be completed in the proxy object.

Code examples

// 抽象主题
interface Subject {
    
    
    void operation();
}

// 具体主题
class RealSubject implements Subject {
    
    
    public void operation() {
    
    
        System.out.println("RealSubject operation");
    }
}

// 代理类
class Proxy implements Subject {
    
    
    private RealSubject realSubject;

    public void operation() {
    
    
        beforeOperation();
        if (realSubject == null) {
    
    
            realSubject = new RealSubject();
        }
        realSubject.operation();
        afterOperation();
    }

    private void beforeOperation() {
    
    
        System.out.println("Proxy before operation");
    }

    private void afterOperation() {
    
    
        System.out.println("Proxy after operation");
    }
}

// 使用示例
public class Main {
    
    
    public static void main(String[] args) {
    
    
        Proxy proxy = new Proxy();
        proxy.operation();
    }
}

Advantages and Disadvantages

advantage:

  • You can control access to objects and add additional processing when accessing objects.
  • The proxy mode follows the opening and closing principle. The client does not need to modify the code of the original object, it only needs to use the proxy object.

shortcoming:

  • The proxy pattern increases the complexity of the system because new objects are introduced.
  • May reduce system performance because proxy objects require additional processing logic.

Compare with other modes

  • Proxy pattern and decorator pattern: Both involve the encapsulation of objects, but the decorator pattern focuses on dynamically adding functions to objects, while the proxy pattern focuses on controlling access to objects.
  • Proxy mode and adapter mode: Both involve the conversion of objects, but the adapter mode focuses on adapting objects with different interfaces into a unified interface, while the proxy mode focuses on controlling access to objects.
  • Proxy mode and appearance mode: Both involve encapsulation, but appearance mode focuses on providing a unified interface, while proxy mode focuses on controlling access to objects.

8. Decorator mode

Introduction

The Decorator pattern is a structural design pattern that allows you to dynamically add additional functionality to an object. The decorator pattern wraps the original object with an additional object and performs additional operations before and after calling the original object's methods.

scenes to be used

  • When you need to dynamically add additional functionality or behavior to an object, you can use the decorator pattern. For example, add logging, performance statistics, caching and other functions to the object without modifying the original class.
  • The decorator pattern can be used when you want more flexibility in inheritance relationships. The decorator pattern allows you to dynamically add additional functions to objects, avoiding the class explosion problem caused by static inheritance.

Code examples

# 抽象组件
class Component:
    def operation(self):
        pass

# 具体组件
class ConcreteComponent(Component):
    def operation(self):
        print("ConcreteComponent operation")

# 装饰器基类
class Decorator(Component):
    def __init__(self, component):
        self._component = component

    def operation(self):
        self._component.operation()

# 具体装饰器
class ConcreteDecoratorA(Decorator):
    def operation(self):
        print("ConcreteDecoratorA operation")
        super().operation()

class ConcreteDecoratorB(Decorator):
    def operation(self):
        super().operation()
        print("ConcreteDecoratorB operation")

# 使用示例
component = ConcreteComponent()
decoratorA = ConcreteDecoratorA(component)
decoratorB = ConcreteDecoratorB(decoratorA)
decoratorB.operation()

Advantages and Disadvantages

advantage:

  • Additional functionality can be added dynamically to an object without modifying the original object's code.
  • The decorator pattern follows the opening and closing principle, allowing you to add new functionality to an object without modifying existing code.

shortcoming:

  • It increases the complexity of the system, and it is necessary to avoid excessive nesting of decorators.
  • You need to pay attention to the order of decorators, because the order in which decorators are executed may affect the final result.

Compare with other modes

  • Decorator pattern and proxy pattern: Both involve object packaging, but the decorator pattern focuses on dynamically adding functionality, while the proxy pattern focuses on controlling access to objects.
  • Decorator pattern and adapter pattern: Both involve the packaging of objects, but the adapter pattern focuses on adapting objects with different interfaces into a unified interface, while the decorator pattern focuses on dynamically adding functionality.
  • Decorator pattern and bridge pattern: Both involve the packaging of objects, but the decorator pattern focuses on dynamically adding functionality to the object, while the bridge pattern focuses on decoupling the abstract part and the implementation part.

Guess you like

Origin blog.csdn.net/jingyoushui/article/details/133048945