当前位置: 首页 > news >正文

设计模式:结构型模式

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 {@Overridepublic void request() {specificRequest();}
}// 对象适配器
class ObjectAdapter implements Target {private Adaptee adaptee;public ObjectAdapter(Adaptee adaptee) {this.adaptee = adaptee;}@Overridepublic void request() {adaptee.specificRequest();}
}

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 {@Overridepublic void operationImpl() {System.out.println("ConcreteImplementorA operationImpl called");}
}// 具体实现类B
class ConcreteImplementorB implements Implementor {@Overridepublic void operationImpl() {System.out.println("ConcreteImplementorB operationImpl called");}
}// 桥接模式的具体实现
class RefinedAbstraction extends Abstraction {public RefinedAbstraction(Implementor implementor) {super(implementor);}@Overridepublic void operation() {implementor.operationImpl();}
}

2.3 桥接模式的优缺点

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

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

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

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

3. 组合模式 (Composite Pattern)

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

3.1 组合模式的概念和作用

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

3.2 组合模式的结构和实现

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

// 抽象组件类
interface Component {void operation();
}// 叶子节点类
class Leaf implements Component {@Overridepublic 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);}@Overridepublic void operation() {for (Component component : children) {component.operation();}}
}

3.3 组合模式的优缺点

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

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

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

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

4. 装饰器模式 (Decorator Pattern)

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

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

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

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

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

// 抽象组件类
interface Component {void operation();
}// 具体组件类
class ConcreteComponent implements Component {@Overridepublic void operation() {System.out.println("ConcreteComponent operation called");}
}// 抽象装饰器类
abstract class Decorator implements Component {protected Component component;public Decorator(Component component) {this.component = component;}@Overridepublic void operation() {component.operation();}
}// 具体装饰器类
class ConcreteDecorator extends Decorator {public ConcreteDecorator(Component component) {super(component);}@Overridepublic void operation() {super.operation();addedBehavior();}private void addedBehavior() {System.out.println("Added behavior by ConcreteDecorator");}
}

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();}
}

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;}@Overridepublic 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);}
}

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.");}
}

7.4 代理模式的优缺点

优点

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

缺点

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

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

  • 对外服务接口的访问控制与权限验证。
  • 远程接口的访问与数据传输。
  • 延迟加载大对象或耗时操作。

相关文章:

  • 初学Vue总结
  • NLP - 神经网络与反向传播
  • 【c++】stack和queue模拟实现
  • 深度神经网络联结主义的本质
  • 【Django】执行查询—跨关系查询中的跨多值关联问题
  • 位运算第二弹
  • 单词倒排——c语言解法
  • proteus8.15图文安装教程
  • ShardingJdbc实战-ShardingJdbc配置及读写分离
  • [FT]chatglm2微调
  • 【C++从0到王者】第四十六站:图的深度优先与广度优先
  • STM32USART串口数据包
  • 字典树基础,朴素字符串查找
  • MySQL 用户账号迁移
  • 小白的matlab简单应用
  • JS 中的深拷贝与浅拷贝
  • 【407天】跃迁之路——程序员高效学习方法论探索系列(实验阶段164-2018.03.19)...
  • AzureCon上微软宣布了哪些容器相关的重磅消息
  • ERLANG 网工修炼笔记 ---- UDP
  • Invalidate和postInvalidate的区别
  • Java 23种设计模式 之单例模式 7种实现方式
  • PHP 7 修改了什么呢 -- 2
  • Synchronized 关键字使用、底层原理、JDK1.6 之后的底层优化以及 和ReenTrantLock 的对比...
  • vue-cli3搭建项目
  • 开年巨制!千人千面回放技术让你“看到”Flutter用户侧问题
  • 如何正确配置 Ubuntu 14.04 服务器?
  • 写代码的正确姿势
  • 一个SAP顾问在美国的这些年
  • HanLP分词命名实体提取详解
  • UI设计初学者应该如何入门?
  • 从如何停掉 Promise 链说起
  • 国内唯一,阿里云入选全球区块链云服务报告,领先AWS、Google ...
  • 专访Pony.ai 楼天城:自动驾驶已经走过了“从0到1”,“规模”是行业的分水岭| 自动驾驶这十年 ...
  • ​LeetCode解法汇总307. 区域和检索 - 数组可修改
  • ​总结MySQL 的一些知识点:MySQL 选择数据库​
  • # Pytorch 中可以直接调用的Loss Functions总结:
  • # 手柄编程_北通阿修罗3动手评:一款兼具功能、操控性的电竞手柄
  • # 透过事物看本质的能力怎么培养?
  • ## 临床数据 两两比较 加显著性boxplot加显著性
  • $ git push -u origin master 推送到远程库出错
  • (2)MFC+openGL单文档框架glFrame
  • (4)通过调用hadoop的java api实现本地文件上传到hadoop文件系统上
  • (Matalb回归预测)PSO-BP粒子群算法优化BP神经网络的多维回归预测
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (二)基于wpr_simulation 的Ros机器人运动控制,gazebo仿真
  • (接口封装)
  • (四)Android布局类型(线性布局LinearLayout)
  • (四)库存超卖案例实战——优化redis分布式锁
  • (未解决)jmeter报错之“请在微信客户端打开链接”
  • (一)VirtualBox安装增强功能
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • (转)Android学习系列(31)--App自动化之使用Ant编译项目多渠道打包
  • (转)可以带来幸福的一本书
  • (转载)虚幻引擎3--【UnrealScript教程】章节一:20.location和rotation
  • (最简单,详细,直接上手)uniapp/vue中英文多语言切换