当前位置:   article > 正文

设计模式:结构型模式

设计模式:结构型模式

1. 适配器模式 (Adapter Pattern)

适配器模式是一种结构型设计模式,旨在将一个类的接口转换成客户端所期待的另一个接口,从而使原本由于接口不兼容而无法一起工作的类能够协同工作。适配器模式通常用于需要复用现有类但其接口与要求不匹配的情况。

1.1 适配器模式的概念和作用

适配器模式允许接口不兼容的类可以相互合作,其作用在于解决不同接口之间的兼容性问题,使得原本不兼容的类可以协同工作。它允许我们创建一个包装器 (Adapter),该包装器实现了客户端所期待的目标接口,并将调用转发给被包装对象。

1.2 对象适配器和类适配器的区别

在适配器模式中,有两种常见的实现方式:对象适配器和类适配器。

  • 对象适配器:适配器持有被适配对象的实例,并在适配器中调用被适配对象的方法来实现目标接口。
  • 类适配器:适配器继承了被适配对象,同时实现了目标接口,从而使得适配器可以作为被适配对象的子类被使用。

1.3 适配器模式的结构和实现

适配器模式的结构包括:目标接口 (Target)、适配器 (Adapter)、被适配对象 (Adaptee)。

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

// 被适配对象
class Adaptee {
    public void specificRequest() {
        System.out.println("Adaptee's specificRequest called");
    }
}

// 类适配器
class ClassAdapter extends Adaptee implements Target {
    @Override
    public void request() {
        specificRequest();
    }
}

// 对象适配器
class ObjectAdapter implements Target {
    private Adaptee adaptee;

    public ObjectAdapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public void request() {
        adaptee.specificRequest();
    }
}
  • 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

1.4 适配器模式的优缺点

  • 优点:
    • 使得客户端可以调用不兼容接口的对象。
    • 可以封装已有的类,提高代码复用性。
  • 缺点:
    • 类适配器需要多重继承,不够灵活,只能适配适配者的接口。
    • 对象适配器需要额外的对象引用,增加了系统的复杂度。

1.5 适配器模式在实际项目中的应用场景

适配器模式常用于以下场景:

  • 已有类的接口与现有系统不兼容。
  • 在不破坏封装性的前提下,需要将一个类适配到另一个接口。
  • 需要复用一个类,但其接口与其他类不兼容。

2. 桥接模式 (Bridge Pattern)

桥接模式是一种结构型设计模式,旨在将抽象部分与实现部分分离,使它们可以独立地变化。桥接模式通过将抽象部分和实现部分分开,使它们可以独立地进行扩展和变化,从而降低它们之间的耦合度。

2.1 桥接模式的概念和作用

桥接模式的核心思想是将抽象与实现分离,使它们可以独立变化,相互之间解耦。这样一来,抽象部分和实现部分可以分别进行扩展,而不会相互影响,从而提高了系统的灵活性和可扩展性。

2.2 桥接模式的结构和实现

在桥接模式中,有两个重要的角色:抽象类 (Abstraction) 和实现类 (Implementor)。抽象类定义了抽象部分的接口,而实现类则负责实现抽象部分的具体功能。

// 抽象类
abstract class Abstraction {
    protected Implementor implementor;

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

    public abstract void operation();
}

// 实现类接口
interface Implementor {
    void operationImpl();
}

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

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

// 桥接模式的具体实现
class RefinedAbstraction extends Abstraction {
    public RefinedAbstraction(Implementor implementor) {
        super(implementor);
    }

    @Override
    public void operation() {
        implementor.operationImpl();
    }
}
  • 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

2.3 桥接模式的优缺点

  • 优点:
    • 分离抽象部分和实现部分,使得系统更加灵活。
    • 可以独立地扩展抽象部分和实现部分。
    • 符合开闭原则,对扩展开放,对修改关闭。
  • 缺点:
    • 增加了系统的复杂度,需要同时设计抽象类和实现类的层次结构。

2.4 桥接模式在实际项目中的应用场景

桥接模式常用于以下场景:

  • 当一个类需要多个变化维度时,使用桥接模式可以将各个维度分离,使得每个维度可以独立变化。
  • 当需要对抽象部分和实现部分进行独立扩展时,可以使用桥接模式。

3. 组合模式 (Composite Pattern)

组合模式是一种结构型设计模式,它允许将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户可以统一对待单个对象和组合对象,从而简化了客户端的代码。

3.1 组合模式的概念和作用

组合模式的核心思想是将对象组织成树形结构,使得客户端可以统一处理单个对象和组合对象。这样一来,用户可以像处理单个对象一样处理组合对象,无需关心其内部结构。

3.2 组合模式的结构和实现

在组合模式中,有两个重要的角色:组件 (Component) 和叶子节点 (Leaf)、容器节点 (Composite)。

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

// 叶子节点类
class Leaf implements Component {
    @Override
    public void operation() {
        System.out.println("Leaf operation called");
    }
}

// 容器节点类
class Composite implements Component {
    private List<Component> children = new ArrayList<>();

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

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

    @Override
    public void operation() {
        for (Component component : children) {
            component.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

3.3 组合模式的优缺点

  • 优点:
    • 统一对待单个对象和组合对象,简化了客户端代码。
    • 可以动态地增加或删除组合对象,更灵活。
  • 缺点:
    • 增加了系统的复杂性,需要设计额外的层次结构。
    • 不太容易限制组合对象的类型。

3.4 组合模式在实际项目中的应用场景

组合模式常用于以下场景:

  • 表示树形结构的数据,如文件系统、组织架构等。
  • 图形界面中的布局管理器,将控件组织成嵌套的层次结构。
  • 菜单管理系统,将菜单项和子菜单组织成树形结构。

4. 装饰器模式 (Decorator Pattern)

装饰器模式是一种结构型设计模式,允许向现有对象动态地添加新功能,同时又不改变其结构。这种模式对于扩展类的功能非常有用,同时又保持了类的简单性和可读性。

4.1 装饰器模式的概念和作用

装饰器模式允许在不改变现有对象结构的情况下,动态地添加新功能。它通过创建一个装饰器类,该类包含一个指向原始对象的引用,并实现与原始对象相同的接口。通过将装饰器类的对象包裹在原始对象周围,可以逐步添加新的行为。

4.2 装饰器模式的结构和实现

在装饰器模式中,有以下几个关键角色:组件 (Component)、具体组件 (ConcreteComponent)、装饰器 (Decorator)、具体装饰器 (ConcreteDecorator)。

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

// 具体组件类
class ConcreteComponent implements Component {
    @Override
    public void operation() {
        System.out.println("ConcreteComponent operation called");
    }
}

// 抽象装饰器类
abstract class Decorator implements Component {
    protected Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public void operation() {
        component.operation();
    }
}

// 具体装饰器类
class ConcreteDecorator extends Decorator {
    public ConcreteDecorator(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation();
        addedBehavior();
    }

    private void addedBehavior() {
        System.out.println("Added behavior by ConcreteDecorator");
    }
}
  • 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

4.3 装饰器模式的优缺点

  • 优点:
    • 可以动态地添加或删除对象的功能,灵活性高。
    • 遵循开闭原则,不需要修改现有代码就可以添加新功能。
  • 缺点:
    • 可能会产生大量的具体装饰器类,增加了系统的复杂性。
    • 客户端需要了解装饰器和被装饰对象的区别,容易混淆。

4.4 装饰器模式在实际项目中的应用场景

装饰器模式常用于以下场景:

  • Java I/O 类库中的 InputStream 和 OutputStream 就是使用了装饰器模式,通过组合不同的装饰器类来实现不同的功能。
  • GUI 应用程序中的窗口和控件,通过装饰器模式可以动态地添加边框、滚动条等装饰。
  • Web 开发中的过滤器、拦截器等功能,也可以使用装饰器模式来实现。

5. 外观模式 (Facade Pattern)

外观模式是一种结构型设计模式,提供了一个统一的接口,用于访问子系统中的一群接口。它隐藏了子系统的复杂性,使得客户端更加容易使用。

5.1 外观模式的概念和作用

外观模式的核心思想是提供一个简单的接口,隐藏了系统的复杂性,并将系统的子模块组织成一个更大的系统。这样,客户端只需要与外观对象进行交互,而不需要了解内部子系统的细节。

5.2 外观模式的结构和实现

在外观模式中,有以下几个关键角色:外观 (Facade)、子系统 (Subsystem)。

// 子系统类
class Subsystem1 {
    public void operation1() {
        System.out.println("Subsystem1 operation");
    }
}

class Subsystem2 {
    public void operation2() {
        System.out.println("Subsystem2 operation");
    }
}

class Subsystem3 {
    public void operation3() {
        System.out.println("Subsystem3 operation");
    }
}

// 外观类
class Facade {
    private Subsystem1 subsystem1;
    private Subsystem2 subsystem2;
    private Subsystem3 subsystem3;

    public Facade() {
        subsystem1 = new Subsystem1();
        subsystem2 = new Subsystem2();
        subsystem3 = new Subsystem3();
    }

    public void operation() {
        subsystem1.operation1();
        subsystem2.operation2();
        subsystem3.operation3();
    }
}
  • 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

5.3 外观模式的优缺点

  • 优点:
    • 简化了客户端与子系统之间的交互,降低了耦合度。
    • 客户端不需要了解子系统的内部结构,减少了对子系统的直接依赖。
    • 提高了代码的灵活性和可维护性。
  • 缺点:
    • 如果外观对象过于臃肿,可能会变得难以维护和理解。

5.4 外观模式在实际项目中的应用场景

外观模式常用于以下场景:

  • 复杂系统的接口简化:当一个系统包含多个子系统,并且子系统之间存在复杂的依赖关系时,可以使用外观模式来简化客户端与系统之间的交互。
  • 封装不稳定的接口:当一个系统中的某些接口频繁变化,但是客户端不希望因此受到影响时,可以使用外观模式来封装这些不稳定的接口。

6. 享元模式 (Flyweight Pattern)

享元模式是一种结构型设计模式,旨在通过共享对象来最小化内存使用和提高性能。它适用于大量相似对象的场景,通过共享内部状态来减少内存占用。

6.1 享元模式的概念和作用

享元模式的核心思想是共享对象以减少内存占用和提高性能。在享元模式中,对象分为内部状态和外部状态。内部状态是可以共享的,而外部状态是不可共享的。通过共享内部状态,可以减少系统中重复对象的数量,从而节省内存。

6.2 享元模式的结构和实现

在享元模式中,有以下几个关键角色:享元工厂 (FlyweightFactory)、具体享元 (ConcreteFlyweight)、非共享具体享元 (UnsharedConcreteFlyweight)、享元接口 (Flyweight)。

// 享元接口
interface Flyweight {
    void operation();
}

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

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

    @Override
    public void operation() {
        System.out.println("ConcreteFlyweight: Intrinsic State = " + intrinsicState);
    }
}

// 享元工厂
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);
    }
}
  • 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

6.3 享元模式的优缺点

  • 优点:
    • 减少内存占用:通过共享内部状态,可以减少系统中重复对象的数量,节省内存空间。
    • 提高性能:由于减少了对象数量,可以提高系统的性能。
  • 缺点:
    • 增加了系统复杂性:引入了共享对象的管理机制,增加了系统的复杂度。
    • 限制外部状态:外部状态不可共享,可能导致一些不便之处。

6.4 享元模式在实际项目中的应用场景

享元模式常用于以下场景:

  • 文字编辑器中的字符共享:在文字编辑器中,如果存在大量相同字符,可以使用享元模式共享这些字符对象,减少内存占用。
  • 棋盘游戏中的棋子管理:在棋盘游戏中,如果存在大量相同的棋子对象,可以使用享元模式共享这些棋子对象,提高性能。

7. 代理模式 (Proxy Pattern)

代理模式是一种结构型设计模式,用于控制对其他对象的访问。

7.1 代理模式的概念和作用

代理模式充当了客户端和目标对象之间的中介,控制对目标对象的访问。它通常用于以下情况:

  • 远程代理:控制对远程对象的访问,例如在网络上访问对象。
  • 虚拟代理:延迟加载目标对象,直到真正需要时才创建。
  • 保护代理:控制对目标对象的访问权限,验证客户端的请求是否合法。
  • 缓存代理:为昂贵的操作结果提供缓存,避免重复计算。

7.2 静态代理和动态代理的区别

  • 静态代理:在编译时已经确定代理类和目标类的关系,代理类需要显式地实现与目标类相同的接口或继承相同的父类。缺点是每个代理类只能代理一个目标类,不够灵活。
  • 动态代理:在运行时动态生成代理类,无需提前定义代理类。Java中的动态代理是通过 java.lang.reflect.Proxy 类实现的,可以代理任意接口。相比静态代理更灵活,但性能上略有损失。

7.3 代理模式的结构和实现

代理模式通常包含以下角色:

  • 抽象主题 (Subject):定义了代理类和真实主题类的公共接口,客户端通过此接口访问真实主题。
  • 真实主题 (Real Subject):实现了抽象主题接口,是代理模式中的实际业务逻辑。
  • 代理类 (Proxy):保存了一个真实主题对象的引用,可以控制对真实主题的访问,在必要时创建或删除真实主题对象。

示例代码:

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

// 真实主题
class RealSubject implements Subject {
    public void request() {
        System.out.println("RealSubject: Handling request.");
    }
}

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

    public Proxy() {
        this.realSubject = new RealSubject();
    }

    public void request() {
        System.out.println("Proxy: Pre-processing request.");
        realSubject.request();
        System.out.println("Proxy: Post-processing 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

7.4 代理模式的优缺点

优点

  • 可以实现对目标对象的控制,保护目标对象和客户端的透明性。
  • 可以实现远程代理、虚拟代理、保护代理等多种功能。

缺点

  • 由于增加了代理类,可能导致代码结构复杂化。
  • 静态代理需要提前定义代理类,不够灵活;动态代理性能稍逊于静态代理。

7.5 代理模式在实际项目中的应用场景

  • 对外服务接口的访问控制与权限验证。
  • 远程接口的访问与数据传输。
  • 延迟加载大对象或耗时操作。
声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号