快速入门C#设计模式【2】结构型模式

2024-08-13 19:29:25 浏览数 (3)

结构型模式

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

适配器模式(Adapter Pattern)

适配器模式(Adapter Pattern)是一种结构型设计模式,它允许不兼容的接口之间可以一起工作。这种模式通常用于系统后期维护和扩展过程中,帮助已存在的系统与第三方库、API 或者是遗留系统进行交互,而无需修改原有代码。

适配器模式的组成

适配器模式通常包括以下几个组件:

  • 目标(Target):定义客户期望使用的特定域相关接口。
  • 客户(Client):与符合目标接口的对象协作。
  • 被适配者(Adaptee):一个已经存在的接口,需要适配。这个接口需要被转换,因为它的设计不能满足目标接口的需求。
  • 适配器(Adapter):适配器把原接口转换为目标接口。

示例:电源适配器

假设有一个简单的场景:一个美国制造的电器只能接受120伏的电压,而欧洲的标准电压是230伏。我们需要一个电源适配器来使这个电器能在欧洲正常工作。

首先,定义目标接口,即客户希望使用的接口:

然后是已存在的类,即被适配者:

接着,实现适配器类,使其兼容目标接口:

最后,客户端代码演示如何使用适配器:

在这个示例中,SocketAdapter 类通过将 AmericanSocket 类包装进一个实现了 IEuropeanSocket 接口的适配器中,使得原本只能接受120伏电压的美国电器可以在230伏的欧洲电压下安全工作。适配器负责接口之间的转换和兼容性处理,客户端代码则可以保持不变,依然使用期望的接口进行操作。这样的设计增强了代码的可维护性和扩展性.

桥接模式(Bridge Pattern)

桥接模式(Bridge Pattern)是一种结构型设计模式,用于将抽象与其实现分离,使得两者可以独立地变化。这种模式通过提供一个桥接结构,使得抽象部分的代码可以与接口实现部分的代码分离,从而减少彼此间的依赖关系。

桥接模式的组成

桥接模式通常包含以下几个部分:

  • 抽象(Abstraction):定义抽象类的接口。它持有一个对实现部分对象的引用,即实现(Implementor)。
  • 扩展抽象(Refined Abstraction):扩展抽象类从抽象类派生,并实现其中定义的抽象方法。
  • 实现者(Implementor):定义实现类的接口,这个接口不需要与抽象类的接口完全一致;事实上,这两个接口可以完全不同。
  • 具体实现(Concrete Implementor):实现 Implementor 接口并定义其具体实现的类。

示例:遥控器和电视

假设我们要设计一个遥控器系统,不同品牌的电视可以通过不同类型的遥控器进行控制。遥控器就是抽象部分,而电视就是实现部分。

1. 实现者接口(Implementor)

2. 具体实现(Concrete Implementor)

为两种品牌的电视实现上述接口:

3. 抽象(Abstraction)

定义遥控器的抽象类:

4. 扩展抽象(Refined Abstraction)

实现具体的遥控器类:

5. 客户端使用

桥接模式使得抽象部分和实现部分可以独立扩展,不仅提高了系统的灵活性,还使得代码更易于维护。在这个例子中,添加一个新品牌的电视或者改变遥控器的设计不会影响到另一方,这正是桥接模式所提供的优势。

组合模式(Composite Pattern)

组合模式(Composite Pattern)是一种结构型设计模式,它允许你将对象组合成树形结构以表示部分-整体的层次结构。组合模式使得客户端对单个对象和组合对象的使用具有一致性。

组合模式的组成

组合模式主要包括以下几个角色:

  • 组件(Component):这是一个抽象角色,为组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理子部件。
  • 叶节点(Leaf):在组合中表示叶节点对象,叶节点没有子节点。
  • 复合组件(Composite):定义有子部件的那些部件的行为。存储子部件,并实现与子部件有关的操作。

示例:文件系统

在这个示例中,我们将使用组合模式来构建一个简单的文件系统,包括文件和文件夹。

1. 组件接口

2. 叶节点(Leaf)

3. 复合组件(Composite)

4. 客户端使用

使用以及执行结果:

在这个例子中,Directory 类(复合组件)可以包含其他 Directory 对象或 File 对象(叶节点),形成一个树形结构。每个组件都实现了 FileSystemComponent 接口,这使得客户端在处理文件和文件夹时可以具有一致的方式。通过调用 Display 方法,可以展示整个文件系统的结构,展示每个文件和文件夹的层次。这种设计使得添加或删除新的文件类型或文件夹时,对其他代码的影响最小,体现了组合模式的优势,即“使用户对单个对象和组合对象的使用具有一致性”。

装饰模式(Decorator Pattern)

装饰模式(Decorator Pattern)是一种结构型设计模式,它允许用户在不修改现有对象的结构的情况下,向对象添加新的功能。装饰模式通过创建一个包含目标对象的包装对象来实现新功能的添加,这样既扩展了对象的功能,也遵守了开闭原则(对扩展开放,对修改关闭)。

装饰模式的组成

装饰模式主要涉及以下几个角色:

  • 抽象组件(Component):定义一个对象接口,可以给这些对象动态地添加职责。
  • 具体组件(ConcreteComponent):定义了一个具体的对象,也可以给这个对象添加一些职责。
  • 装饰角色(Decorator):持有一个组件(Component)对象的引用,并定义了一个与组件接口一致的接口。
  • 具体装饰(ConcreteDecorator):具体实现装饰角色提供的装饰。

示例:咖啡店

在这个例子中,我们将使用装饰模式来模拟咖啡店的订单系统,其中顾客可以选择不同类型的咖啡,并可添加多种调料。

1. 抽象组件(Component)

2. 具体组件(ConcreteComponent)

定义几种咖啡:

3. 装饰角色(Decorator)

4. 具体装饰(ConcreteDecorator)

定义几种调料装饰:

5. 客户端使用

实际调用和结果输出如下

在这个示例中,Espresso 和 HouseBlend 是具体的咖啡,分别实现了 Beverage 抽象类。Mocha 和 Hand 是装饰者,它们继承自 CondimentDecorator,这是一个抽象装饰类。每个装饰者类增加了额外的行为(添加调料)并调整了价格。通过装饰者,可以灵活地添加或修改对象的行为,同时保持代码的简洁和可维护性。这种方式非常适合于功能频繁变化的系统。

外观模式(Facade Pattern)

外观模式(Facade Pattern)是一种常用的软件设计模式,它提供了一个高层次的接口,使得系统更加容易使用。外观模式常常用于为复杂的系统或库提供一个简单的接口,减少系统间的依赖,增加子系统的独立性和可移植性。

设计目的

外观模式的主要目的是隐藏系统的复杂性,提供一个简化的接口给客户端。通过这种方式,如果后续系统内部发生变化,客户端代码不需要改动;只需要在外观类中调整即可。

使用场景

  • 系统有很多分散的类,操作起来很复杂,需要一个简化的接口。
  • 客户端与多个子系统之间存在很大的依赖性,引入外观模式将这些子系统封装起来,提高子系统的独立性和安全性。
  • 在层次化结构中,可以使用外观模式定义系统的每一层的入口。

实现步骤

  1. 确定要简化的子系统的功能集。
  2. 创建一个外观类,它将负责调用子系统的方法,处理客户端的请求。
  3. 客户端通过外观类与子系统交互,降低了系统的复杂性。

示例

假设有一个复杂的音频系统,包含了多个组件,如音量控制、信号处理、音频播放等。我们可以创建一个外观类,来简化和统一这些操作。

C#代码实现

首先,定义一些子系统类:

接下来,创建外观类:

最后,使用方式以及运行效果:

在上述例子中,AudioFacade 类提供了一个简单的接口 PlaySound,客户端通过这个接口可以很容易地播放音频而不需要直接与复杂的子系统交互。这样,客户端代码变得更简单,同时也增强了系统各部分之间的独立性。

享元模式(Flyweight Pattern)

享元模式(Flyweight Pattern)是一种用于性能优化的结构型设计模式。这个模式通过共享尽可能多的相似对象来减少内存使用,特别适用于处理大量对象时,其中许多对象由重复的状态组成。

设计目的

享元模式的主要目的是在有大量相似对象的情况下,通过共享尽可能多的对象以减少内存消耗。这通常是通过将这些对象的状态分为“内部状态”(intrinsic)和“外部状态”(extrinsic)来实现的:

  • 内部状态是存储在享元对象内部的,不会随环境改变而改变。
  • 外部状态是根据场景外部变化的,并需要客户端提供。

使用场景

  • 当一个程序使用了大量的对象,这些对象大部分状态可以被外部化时。
  • 当因为使用大量对象,造成很高的内存开销时。
  • 当对象的多数状态都可以变为可共享的时,可以将这些对象替换为少量的共享对象。

示例

假设有一个文档编辑器,它可以设置字符的样式。每个字符可以是一个对象,但是样式(如字体、大小)很可能在多个字符中是相同的。这里,样式可以作为内部状态,由享元对象共享,而每个字符的位置可以作为外部状态由客户端代码来管理。

C#代码实现

首先,定义享元类及接口:

然后,创建享元工厂:

具体使用和运行结果如下:

代理模式(Proxy Pattern)

代理模式(Proxy Pattern)是一种结构型设计模式,它通过提供一个替代品或代表其他对象来控制对这个对象的访问。代理模式可以用于多种情景,例如延迟初始化、访问控制、日志记录和智能引用等。它主要用于控制和管理对象的访问。

设计目的

代理模式的主要目的是:

  • 控制对某个对象的访问。
  • 延迟对象的创建和初始化,从而优化资源和内存的使用。
  • 作为调用方和实际对象之间的中介,添加额外的功能,如安全检查、日志等。

使用场景

  • 当需要为一个昂贵的操作提供一个轻量级的处理接口时,如对资源的密集型访问。
  • 当需要对原始对象进行访问控制时,提供额外的安全层。
  • 在需要管理生命周期或结果缓存时。

示例

假设有一个文档加载和显示系统,我们想通过使用代理模式来控制对文档的访问,假设加载文档是一个资源密集的操作。

C#代码实现

首先,定义一个文档接口和实现该接口的实际类:

接着,创建代理类:

使用方式和运行效果如下:

以上就是结构型设计模式的所有演示内容,感兴趣可以上gitee获取以上测试的源码:

https://gitee.com/dreamer_j/design-patterns.git

0 人点赞