• 8种结构型设计模式对比


    一、适配器模式

    简介

    适配器模式是一种结构型设计模式,它用于将不兼容的接口转换为可兼容的接口。适配器模式允许两个不兼容的类能够协同工作,通过将一个类的接口转换为另一个类所期望的接口形式。这样就能够在不修改现有代码的情况下,使两个不兼容的类能够相互协作。

    使用场景

    适配器模式通常在以下场景中使用:

    • 当需要将现有类的接口转换为其他接口时,可以使用适配器模式。
    • 当需要与一个或多个现有类进行适配以实现特定功能时,适配器模式是一个非常有用的工具。

    代码案例

    // 目标接口
    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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    优点

    • 适配器模式能够让两个不兼容的接口能够协同工作,提高代码的复用性和灵活性。
    • 适配器模式能够让客户端代码与具体类解耦,减少了客户端代码对具体类的依赖。

    缺点

    • 适配器模式可能需要创建更多的类来实现适配器和被适配者之间的关系,增加了代码的复杂性。
    • 适配器模式可能会引入一定的性能损失,因为需要通过适配器来实现接口转换。

    对比其他模式

    • 适配器模式和桥接模式类似,但是适配器模式用于处理接口转换,而桥接模式用于处理抽象和实现的分离。
    • 适配器模式和装饰器模式类似,但是适配器模式用于接口转换,而装饰器模式用于动态地给对象添加额外的功能。

    二、桥接模式

    简介

    桥接模式是一种结构型设计模式,它将抽象部分和实现部分分离,使它们可以独立地变化。通过将抽象和实现分离,桥接模式可以使两者能够独立地进行扩展。这种模式的核心目标是通过解耦抽象和实现,来使它们能够相互独立地变化。

    使用场景

    桥接模式通常在以下场景中使用:

    • 当需要抽象和实现能够独立地变化时,可以使用桥接模式。
    • 当需要避免多重继承的情况下,可以使用桥接模式。
    • 当需要改变一个类的实现时,不影响其他使用该类的类时,可以使用桥接模式。

    代码案例

    // 实现部分接口
    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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    优点

    • 桥接模式使抽象部分和实现部分能够独立地变化,解耦了抽象和实现,提高了代码的灵活性和可扩展性。
    • 桥接模式可以在运行时动态地切换实现,不需要修改客户端代码。

    缺点

    • 桥接模式可能会增加系统的复杂性,因为需要创建额外的抽象和实现类来进行桥接。
    • 桥接模式可能会增加系统的开销,因为需要通过桥接来实现抽象和实现的分离。

    对比其他模式

    • 桥接模式和适配器模式类似,但是桥接模式用于处理抽象和实现的分离,而适配器模式用于处理接口转换。
    • 桥接模式和装饰器模式类似,但是桥接模式用于抽象和实现的分离,而装饰器模式用于动态地给对象添加额外的功能。

    三、组合模式

    简介

    组合模式是一种结构型设计模式,它允许将对象组合成树形结构,以表示整体-部分的层次结构。通过使用组合模式,可以以统一的方式处理对象组合和单个对象。

    使用场景

    • 当希望将对象以树形结构组织起来的时候,可以使用组合模式。例如,文件系统中的文件和目录可以使用组合模式来表示,每个目录都可以包含子目录和文件。
    • 当需要对整个对象集合或其中一部分进行处理时,可以使用组合模式。例如,统计一个部门的所有员工的工资总和,可以通过遍历部门的树形结构来计算。

    代码案例

    // 抽象组件
    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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    优缺点

    优点:

    • 可以简化客户端代码,客户端可以统一处理复合对象和叶子对象。
    • 新增或移除组件比较容易,客户端无需关心具体组件的类型。

    缺点:

    • 增加了系统的复杂性,部分情况下可能会加重代码的维护负担。
    • 使用组合模式时,需要权衡透明性和安全性,可能会导致设计模糊。

    与其他模式对比

    • 组合模式和装饰器模式:两者都涉及对象组合,但装饰器模式注重给对象动态添加功能,而组合模式注重树形结构。
    • 组合模式和桥接模式:两者都涉及对象组合,但桥接模式注重将抽象和实现解耦,而组合模式注重树形结构。
    • 组合模式和享元模式:两者都涉及对象共享,但组合模式注重树形结构,共享的是整体,而享元模式注重细粒度对象的共享。

    四、装饰器模式

    简介

    装饰器模式是一种结构型设计模式,它允许动态地给对象添加额外的功能。装饰器模式通过使用额外的对象来包装原始对象,并在调用原始对象的方法前后执行额外的操作。

    使用场景

    • 当需要给对象动态地添加额外功能或行为时,可以使用装饰器模式。例如,为了在运行时对数据库查询结果进行缓存,可以使用装饰器模式来包装查询操作。
    • 当希望继承关系具有更大灵活性时,可以使用装饰器模式。装饰器模式允许动态地给对象添加额外功能,避免了静态继承的限制。

    代码案例

    # 抽象组件
    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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    优缺点

    优点:

    • 可以动态地给对象添加额外的功能,而不需要修改原始对象的代码。
    • 装饰器模式遵循开闭原则,允许在不修改现有代码的情况下,给对象添加新的功能。

    缺点:

    • 增加了系统的复杂性,需要尽量避免过多的装饰器嵌套。
    • 需要注意装饰器的顺序,因为装饰器的执行顺序可能会影响最终结果。

    与其他模式对比

    • 装饰器模式和代理模式:两者都涉及对象包装,但装饰器模式注重动态添加功能,而代理模式注重控制对象的访问。
    • 装饰器模式和适配器模式:两者都涉及对象的包装,但适配器模式注重将不同接口的对象适配为统一接口,而装饰器模式注重动态添加功能。
    • 装饰器模式和桥接模式:两者都涉及对象的包装,但装饰器模式注重给对象动态添加功能,而桥接模式注重将抽象部分和实现部分解耦。

    五、外观模式

    简介

    外观模式是一种结构型设计模式,它提供了一个统一的接口,用于访问子系统的一组接口。外观模式通过封装一组复杂的子系统接口,简化了客户端与子系统之间的交互。

    使用场景

    • 当希望对复杂子系统进行简化并提供统一接口的时候,可以使用外观模式。例如,客户端需要与数据库、缓存、消息队列等多个组件交互时,可以通过外观模式将这些交互封装起来,对外提供统一的接口。
    • 当需要解耦客户端和子系统之间的依赖关系时,可以使用外观模式。

    代码案例

    # 子系统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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    优缺点

    优点:

    • 简化了客户端与子系统之间的交互,客户端只需要与外观类交互即可,不需要了解子系统的细节。
    • 解耦了客户端和子系统的依赖关系,客户端只需要依赖外观类即可。

    缺点:

    • 太多的依赖于外观类可能会导致系统可维护性下降,不利于系统的扩展。

    与其他模式对比

    • 外观模式和适配器模式:两者都涉及封装,但外观模式注重对一组接口的统一封装,而适配器模式注重对不同接口的适配。
    • 外观模式和中介者模式:两者都涉及解耦客户端和子系统的依赖关系,但中介者模式注重通过中介对象进行交互,而外观模式注重提供统一的接口。
    • 外观模式和代理模式:两者都涉及封装,但代理模式注重控制对象的访问,而外观模式注重对一组接口的统一封装。

    六、享元模式

    简介

    享元模式是一种结构型设计模式,它通过共享对象来减少内存使用,以支持大量细粒度的对象。享元模式将对象的状态分为内部状态和外部状态,内部状态可以共享,外部状态可以由客户端传入。

    使用场景

    • 当需要创建大量细粒度对象,并且内部状态可以共享时,可以使用享元模式。例如,网页编辑器中的字母对象,可以通过享元模式来实现共享。
    • 当对象的大部分状态可以从外部传入,并且不依赖于具体对象的时候,可以使用享元模式。

    代码案例

    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");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    优缺点

    优点:

    • 可以减少内存使用,提高系统的性能。
    • 在大规模细粒度对象的场景下,可以节省大量内存空间。

    缺点:

    • 增加了系统的复杂性,需要对外部状态进行管理,可能会引入线程安全问题。
    • 需要权衡在内部状态和外部状态之间的共享程度。

    与其他模式对比

    • 享元模式和单例模式:两者都涉及共享对象,但单例模式注重单一实例,而享元模式注重共享细粒度对象。
    • 享元模式和原型模式:两者都涉及创建对象,但原型模式注重克隆对象,而享元模式注重共享对象。
    • 享元模式和代理模式:两者都涉及对象的封装,但代理模式注重控制对象的访问,而享元模式注重共享对象的内部状态。

    七、代理模式

    简介

    代理模式是一种结构型设计模式,用于控制对象的访问,并在访问对象时添加额外的处理。代理模式通过创建一个代理对象来代替原始对象,客户端使用代理对象进行操作,代理对象在执行操作前后可以添加一些额外的逻辑。

    使用场景

    • 当需要对对象的访问进行控制时,可以使用代理模式。例如,限制对敏感数据的访问,可以创建一个代理对象,在访问敏感数据前进行身份验证。
    • 当需要在访问对象时添加额外的处理逻辑时,可以使用代理模式。例如,记录日志、缓存结果等操作,都可以在代理对象中完成。

    代码案例

    // 抽象主题
    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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    优缺点

    优点:

    • 可以控制对对象的访问,并在访问对象时添加额外的处理。
    • 代理模式遵循开闭原则,客户端不需要修改原始对象的代码,只需要使用代理对象即可。

    缺点:

    • 代理模式增加了系统的复杂性,因为引入了新的对象。
    • 可能会降低系统的性能,因为代理对象需要额外的处理逻辑。

    与其他模式对比

    • 代理模式与装饰器模式:两者都涉及对象的封装,但装饰器模式注重给对象动态添加功能,而代理模式注重控制对象的访问。
    • 代理模式与适配器模式:两者都涉及对象的转换,但适配器模式注重将不同接口的对象适配为统一接口,而代理模式注重控制对象的访问。
    • 代理模式与外观模式:两者都涉及封装,但外观模式注重提供统一接口,而代理模式注重控制对象的访问。

    八、装饰器模式

    简介

    装饰器模式是一种结构型设计模式,允许动态地给对象添加额外的功能。装饰器模式通过使用额外的对象来包装原始对象,并在调用原始对象的方法前后执行额外的操作。

    使用场景

    • 当需要给对象动态地添加额外的功能或行为时,可以使用装饰器模式。例如,在不修改原有类的情况下,为对象添加日志记录、性能统计、缓存等功能。
    • 当希望继承关系具有更大灵活性时,可以使用装饰器模式。装饰器模式允许动态地给对象添加额外的功能,避免了静态继承带来的类爆炸问题。

    代码案例

    # 抽象组件
    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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    优缺点

    优点:

    • 可以动态地给对象添加额外的功能,而不需要修改原始对象的代码。
    • 装饰器模式遵循开闭原则,允许在不修改现有代码的情况下,给对象添加新的功能。

    缺点:

    • 增加了系统的复杂性,需要尽量避免过多的装饰器嵌套。
    • 需要注意装饰器的顺序,因为装饰器的执行顺序可能会影响最终结果。

    与其他模式对比

    • 装饰器模式和代理模式:两者都涉及对象包装,但装饰器模式注重动态添加功能,而代理模式注重控制对象的访问。
    • 装饰器模式和适配器模式:两者都涉及对象的包装,但适配器模式注重将不同接口的对象适配为统一接口,而装饰器模式注重动态添加功能。
    • 装饰器模式和桥接模式:两者都涉及对象的包装,但装饰器模式注重给对象动态添加功能,而桥接模式注重将抽象部分和实现部分解耦。
  • 相关阅读:
    Kotlin中的数组
    AIGC(生成式AI)试用 1 -- 基本文本查询
    用DIV+CSS技术设计的环保主题网站(web前端网页制作课作业)
    2023年U.S.News世界大学排名发布(附TOP100榜单)
    2000-2021年上市公司M&A并购溢价计算数据(含原始数据+Stata代码)
    vue首页多模块布局(标题布局)
    投资理财(待更新,仅供个人使用)
    算法:【位运算】详解、总结、具体推导过程
    272_C++_把当前日期和时间信息转换为一个微秒级别的时间戳,考虑中国时区GMT-8影响以及UTC时间和GMT时间的区分
    第2-1-2章 传统方式安装FastDFS-附FastDFS常用命令
  • 原文地址:https://blog.csdn.net/jingyoushui/article/details/133048945