结构型设计模式详解与总结

一、什么是结构型设计模式

结构型设计模式的主要目的是处理类或对象之间的组合与继承问题,通过组织类和对象来形成更大的结构,帮助我们更好地解决类与类、对象与对象之间的耦合问题。这类模式通过定义如何组合对象来实现新的功能,着重于解决系统中复杂关系的组织和维护,使得系统更加易于扩展和维护。

结构型设计模式主要有以下几种:

  1. 适配器模式(Adapter)
  2. 桥接模式(Bridge)
  3. 装饰者模式(Decorator)
  4. 组合模式(Composite)
  5. 外观模式(Facade)
  6. 享元模式(Flyweight)
  7. 代理模式(Proxy)

接下来,我们将逐一讲解这些结构型设计模式。

二、适配器模式(Adapter Pattern)

2.1 模式介绍

适配器模式将一个类的接口转换成客户端所期待的另一个接口,使原本接口不兼容的类可以一起工作。通过这种模式,开发者无需修改已有代码便能使旧系统与新系统兼容。

2.2 模式结构

适配器模式主要有三个参与者:

  • 目标接口(Target Interface):定义客户端所期待的接口。
  • 适配者类(Adaptee):现有接口,但与目标接口不兼容。
  • 适配器(Adapter):实现目标接口,内部封装适配者类,将适配者的接口转换为目标接口。

2.3 代码示例

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

// 适配者类
public class Adaptee {
    public void specificRequest() {
        System.out.println("调用适配者类中的方法");
    }
}

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

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

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

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Adaptee adaptee = new Adaptee();
        Target target = new Adapter(adaptee);
        target.request();
    }
}

2.4 优缺点

  • 优点

    • 可以让不兼容的类协同工作,不用修改现有类,符合开闭原则。
    • 提高了类的复用性和灵活性。
  • 缺点

    • 增加了系统的复杂性,特别是在过多使用适配器的情况下,代码可读性可能降低。

2.5 适用场景

  • 现有系统的接口不符合需求,且无法修改现有系统时。
  • 希望复用一些现有的类,但这些类的接口与目标接口不兼容。

三、桥接模式(Bridge Pattern)

3.1 模式介绍

桥接模式将抽象部分与它的实现部分分离,使它们都可以独立地变化。这种模式通常用于系统有多个维度的变化时,利用组合而不是继承来应对变化。

3.2 模式结构

桥接模式主要由以下几个角色组成:

  • 抽象类(Abstraction):定义抽象部分的接口,包含一个实现类对象。
  • 扩展抽象类(Refined Abstraction):是抽象类的子类,实现具体的业务方法。
  • 实现类接口(Implementor):定义实现类的接口。
  • 具体实现类(Concrete Implementor):实现 Implementor 接口,负责具体的业务逻辑。

3.3 代码示例

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

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

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

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

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

    public abstract void operation();
}

// 扩展抽象类
public class RefinedAbstraction extends Abstraction {
    public RefinedAbstraction(Implementor implementor) {
        super(implementor);
    }

    @Override
    public void operation() {
        implementor.operationImpl();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Implementor implementorA = new ConcreteImplementorA();
        Abstraction abstraction = new RefinedAbstraction(implementorA);
        abstraction.operation();

        Implementor implementorB = new ConcreteImplementorB();
        abstraction = new RefinedAbstraction(implementorB);
        abstraction.operation();
    }
}

3.4 优缺点

  • 优点

    • 抽象和实现分离,避免了继承层次的急剧膨胀,支持系统的多维度扩展。
    • 提高了系统的扩展性,增加新的实现类或抽象类都非常方便。
  • 缺点

    • 增加了系统的复杂性,理解和实现桥接模式需要额外的努力。

3.5 适用场景

  • 系统需要从多个维度进行扩展时,比如需要在不同平台上显示不同格式的图形。
  • 希望减少子类的数量,减少类的层次结构。

四、装饰者模式(Decorator Pattern)

4.1 模式介绍

装饰者模式动态地给对象添加额外的职责,相比于继承,装饰者模式更加灵活。装饰者模式通过创建一系列装饰类来对原始对象进行增强,使得对象可以灵活地进行扩展。

4.2 模式结构

装饰者模式包括以下角色:

  • 组件接口(Component):定义对象的基本接口。
  • 具体组件(Concrete Component):实现 Component 接口,代表被装饰的对象。
  • 装饰者(Decorator):实现 Component 接口,并持有一个 Component 对象,负责对其进行增强。
  • 具体装饰者(Concrete Decorator):具体实现装饰者逻辑,增强 Component 对象的功能。

4.3 代码示例

// 组件接口
public interface Component {
    void operation();
}

// 具体组件
public class ConcreteComponent implements Component {
    @Override
    public void operation() {
        System.out.println("执行具体组件的操作");
    }
}

// 装饰者类
public class Decorator implements Component {
    protected Component component;

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

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

// 具体装饰者A
public class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component component) {
        super(component);
    }

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

    // 添加新的行为
    private void addedBehavior() {
        System.out.println("具体装饰者A的额外行为");
    }
}

// 具体装饰者B
public class ConcreteDecoratorB extends Decorator {
    public ConcreteDecoratorB(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation();
        System.out.println("具体装饰者B的额外行为");
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Component component = new ConcreteComponent();
        Component decoratorA = new ConcreteDecoratorA(component);
        Component decoratorB = new ConcreteDecoratorB(decoratorA);
        decoratorB.operation();
    }
}

4.4 优缺点

  • 优点

    • 动态地给对象添加新功能,遵循开闭原则。
    • 装饰者模式可以灵活组合功能,使得每个装饰者类的职责单一,增强了可维护性。
  • 缺点

    • 装饰者模式会增加系统的复杂性,特别是在多个装饰者叠加时,代码的调试可能变得困难。

4.5 适用场景

  • 需要动态地给一个对象添加额外功能,且这些功能可以灵活地组合。
  • 希望避免通过继承来扩展对象的功能时。

五、组合模式(Composite Pattern)

5.1 模式介绍

组合模式将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得客户端对单个对象和组合对象的使用具有一致性,常用于表示层次结构的场景。

5.2 模式结构

组合模式包括以下角色:

  • 组件(Component):为组合中的对象声明接口,并提供了子类的默认行为。
  • 叶子(Leaf):代表组合中的叶子对象,没有子节点。
  • 组合(Composite):定义有子节点的组合对象,并实现与叶子节点一致的接口。

5.3 代码示例

// 组件接口
public abstract class Component {
    public void add(Component component) {
        throw new UnsupportedOperationException();
    }

    public void remove(Component component) {
        throw new UnsupportedOperationException();
    }

    public Component getChild(int i) {
        throw new UnsupportedOperationException();
    }

    public abstract void operation();
}

// 叶子对象
public class Leaf extends Component {
    @Override
    public void operation() {
        System.out.println("执行叶子的操作");
    }
}

// 组合对象
public class Composite extends Component {
    private List<Component> children = new ArrayList<>();

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

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

    @Override
    public Component getChild(int i) {
        return children.get(i);
    }

    @Override
    public void operation() {
        for (Component child : children) {
            child.operation();
        }
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Composite root = new Composite();
        root.add(new Leaf());

        Composite subComposite = new Composite();
        subComposite.add(new Leaf());
        root.add(subComposite);

        root.operation();
    }
}

5.4 优缺点

  • 优点

    • 组合模式能清晰地描述对象层次结构,使得客户代码可以一致地操作单个对象和组合对象。
    • 容易扩展新的类型,符合开闭原则。
  • 缺点

    • 设计的层次结构复杂,可能会导致难以维护,特别是在层次过深的情况下。

5.5 适用场景

  • 需要表示对象的部分-整体层次结构时。
  • 希望客户端可以忽略组合对象与单个对象的区别,统一处理它们时。

六、外观模式(Facade Pattern)

6.1 模式介绍

外观模式为子系统中的一组接口提供一个一致的接口,使得子系统更加容易被使用。它通过将复杂的子系统与客户端之间的交互封装起来,简化了客户端的使用难度。

6.2 模式结构

外观模式由以下角色组成:

  • 外观(Facade):提供了与客户端交互的简化接口。
  • 子系统类(Subsystem Classes):复杂的子系统,负责实现子系统的具体功能。

6.3 代码示例

// 子系统A
public class SubsystemA {
    public void operationA() {
        System.out.println("子系统A的操作");
    }
}

// 子系统B
public class SubsystemB {
    public void operationB() {
        System.out.println("子系统B的操作");
    }
}

// 外观类
public class Facade {
    private SubsystemA subsystemA;
    private SubsystemB subsystemB;

    public Facade() {
        subsystemA = new SubsystemA();
        subsystemB = new SubsystemB();
    }

    public void operation() {
        subsystemA.operationA();
        subsystemB.operationB();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.operation();
    }
}

6.4 优缺点

  • 优点

    • 简化了复杂系统的使用,使得系统的交互更加清晰明了。
    • 外观模式提供了子系统和客户端之间的松耦合,增强了系统的可维护性。
  • 缺点

    • 增加了额外的外观类,可能会使系统变得臃肿。

6.5 适用场景

  • 需要简化子系统的复杂交互时。
  • 子系统与客户端之间需要松耦合时。

七、享元模式(Flyweight Pattern)

7.1 模式介绍

享元模式通过共享对象来尽量减少内存消耗,特别适用于大量细粒度对象的场景。它通过将相同的对象共享来减少对象数量,以节省内存。

7.2 模式结构

享元模式主要有以下角色:

  • 享元接口(Flyweight Interface):定义享元对象的接口。
  • 具体享元(Concrete Flyweight):实现享元接口,表示可以共享的对象。
  • 非共享享元(Unshared Flyweight):不可以共享的对象。
  • 享元工厂(Flyweight Factory):负责管理享元对象的创建和缓存,确保每个享元对象可以被共享。

7.3 代码示例

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

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

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

    @Override
    public void operation(String externalState) {
        System.out.println("内部状态:" + intrinsicState + ",外部状态:" + externalState);
    }
}

// 享元工厂
public 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 Client {
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();

        Flyweight flyweight1 = factory.getFlyweight("A");
        flyweight1.operation("外部状态1");

        Flyweight flyweight2 = factory.getFlyweight("A");
        flyweight2.operation("外部状态2");
    }
}

7.4 优缺点

  • 优点

    • 通过共享对象减少内存消耗,特别适用于有大量重复对象的场景。
    • 提高了系统的性能,减少了内存的使用。
  • 缺点

    • 增加了系统的复杂性,享元对象的状态需要区分内部和外部状态。

7.5 适用场景

  • 系统中有大量相似对象时,且这些对象大部分状态可以共享时。
  • 需要优化内存使用,减少对象数量时。

八、代理模式(Proxy Pattern)

8.1 模式介绍

代理模式为另一个对象提供一个代理对象,代理对象控制着对目标对象的访问,代理模式通过创建一个代理类来实现对原对象的控制,使得原对象不直接暴露给客户端。

8.2 模式结构

代理模式包括以下几个角色:

  • 抽象主题(Subject)

:定义目标对象和代理对象的共同接口。

  • 真实主题(RealSubject):实际的业务实现对象,处理实际的业务逻辑。
  • 代理(Proxy):控制对真实主题的访问,负责在调用真实主题之前进行处理。

8.3 代码示例

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

// 真实主题
public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("真实主题的请求处理");
    }
}

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

    @Override
    public void request() {
        if (realSubject == null) {
            realSubject = new RealSubject();
        }
        System.out.println("代理类处理前的操作");
        realSubject.request();
        System.out.println("代理类处理后的操作");
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Subject proxy = new Proxy();
        proxy.request();
    }
}

8.4 优缺点

  • 优点

    • 代理模式可以在不修改目标对象的前提下,通过代理对象扩展目标对象的功能(如权限控制、日志记录、延迟加载等)。
    • 提供了目标对象的间接访问,客户端无需知道具体的目标对象如何实现,可以通过代理来控制访问。
  • 缺点

    • 增加了系统的复杂性,尤其是在多层代理时,可能会影响系统性能。
    • 代理模式可能会造成过多的代理类,增加系统维护成本。

8.5 适用场景

  • 需要控制对对象的访问时,例如在远程调用、权限控制、缓存机制、延迟加载等场景中。
  • 希望通过代理对象在不修改目标对象的情况下增强某些功能时。

九、总结

在设计模式中,结构型设计模式主要关注类和对象的组合,它们通过一定的组合方式来解决系统的扩展问题,同时也提升了系统的灵活性和可维护性。在实际开发过程中,合理选择和使用结构型设计模式,不仅可以简化系统的复杂度,还能提高系统的可扩展性和可维护性。

  • 适配器模式 用于转换接口,使得不兼容的接口可以一起工作。
  • 桥接模式 通过分离抽象和实现,使得它们可以独立变化。
  • 装饰者模式 动态地为对象添加额外的功能,符合开闭原则。
  • 组合模式 将对象组合成树形结构,以实现部分-整体的层次结构。
  • 外观模式 提供了简化子系统使用的统一接口,降低了系统的复杂度。
  • 享元模式 通过共享细粒度对象来减少内存消耗。
  • 代理模式 通过代理对象控制对目标对象的访问,增加了对目标对象访问的灵活性。

每种设计模式都有其独特的适用场景和优缺点,开发者在项目中选择合适的模式,不仅能够提高开发效率,还能增强系统的稳定性和扩展性。通过对这些结构型设计模式的理解和掌握,能够帮助开发者更好地应对复杂系统设计中的挑战,提升代码的质量和可维护性。

在实际的开发工作中,结构型设计模式常常是结合其他设计模式(如创建型模式、行为型模式)一起使用的,它们并非孤立存在,而是相互补充和增强,共同解决系统设计中的复杂问题。掌握这些模式的精髓,能够让开发者在复杂系统设计中游刃有余,打造出高效、灵活、易扩展的系统架构。


通过本篇对结构型设计模式的介绍和总结,希望读者能够对这些模式有一个清晰的理解和认知,并在实际项目中熟练运用,设计出更加健壮和高效的系统。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一休哥助手

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值