装饰模式与外观模式
- 设计模式
- 2024-07-02
- 649热度
- 0评论
一、装饰模式
1.1 概念
装饰模式是一种用于替代继承的技术,它通过无须定义子类的方式来给对象动态的增加职责,使用对象之间的关联关系取代类之间的继承关系。装饰模式降低了系统的耦合度,可以动态增加或删除对象的职责。
定义:动态地给一个对象增加一些额外的职责,就扩展功能而言,装饰模式提供了一种比使用子类更加灵活的替代方案。
1.2 模式结构
-
Component(抽象组件):具体组件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法,定义了可以动态增加任务对象的接口。
-
ConcreteComponent(具体组件):抽象组件的子类,用于定义具体组件对象,实现了抽象组件中声明的方法,装饰类可以给他增加额外的职责。
-
Decorator(抽象装饰类):也是抽象组件的子类,用于给具体组件增加职责,但是具体职责在其子类中实现。它维护一个只想抽象组件对象的引用,通过该引用可以调用装饰之前组件对象的方法,并通过其子类扩展该方法,达到装饰的目的。
-
ConcreteDecorator(具体装饰类):它是抽象装饰类的子类,负责向组件添加新的职责。每个具体装饰类都定义了一些新的行为,可以调用在抽象装饰类中定义的方法,并可以增加新的方法用于扩充对象的行为。
-
核心代码:
public abstract class Component { public abstract void operation(); } public class ConcreteComponent : Component { public override void operation() { // 基本功能实现 Console.WriteLine("基本功能实现"); } } public class Decorator : Component { private Component component; public Decorator(Component component) { this.component = component; } public override void operation() { component.operation(); } } public class ConcreteDecorator : Decorator { public ConcreteDecorator(Component component) : base(component) { } public override void operation() { base.operation(); addBehavior(); } public void addBehavior() { Console.WriteLine("进行扩展"); } } public class Client { public void Main() { Component simple = new ConcreteComponent(); ConcreteDecorator decorator = new ConcreteDecorator(simple); decorator.operation(); } /* * 基本功能实现 * 进行扩展 */ }
1.3 应用实例
为了让系统具有更好的灵活性和可扩展性,克服继承复用所带来的问题,公司使用装饰模式来重构图形界面构件库的设计。
-
Component类:抽象组件
public abstract class Component { public abstract void display(); }
-
ConcreteComponent类:具体实现组件
public class Window : Component { public override void display() { Console.WriteLine("显示窗体"); } } public class TextBox : Component { public override void display() { Console.WriteLine("显示文本框"); } } public class ListBox : Component { public override void display() { Console.WriteLine("显示列表框"); } }
-
ComponentDecorator类:抽象装饰类
public class ComponentDecorator : Component { private Component component; public ComponentDecorator(Component component) { this.component = component; } public override void display() { component.display(); } }
-
ConcreteDecorator类:具体装饰类
public class ScrollBarDecorator : ComponentDecorator { public ScrollBarDecorator(Component component) : base(component) { } public override void display() { AddScrollBar(); base.display(); } public void AddScrollBar() { Console.WriteLine("为组件增加滚动条"); } } public class BlackBorderDecorator : ComponentDecorator { public BlackBorderDecorator(Component component) : base(component) { } public override void display() { AddBlackBorder(); base.display(); } public void AddBlackBorder() { Console.WriteLine("为组件增加黑色边框"); } }
-
Client类:
Component window = new Window(); Component blackWindow = new BlackBorderDecorator(window); blackWindow.display(); Component blackScrollWindow = new ScrollBarDecorator(blackWindow); blackScrollWindow.display(); /* * 为组件增加黑色边框 * 显示窗体 * 为组件增加滚动条 * 为组件增加黑色边框 * 显示窗体 */
1.4 优缺点
- 优点:
- 灵活性和扩展性:装饰模式可以在运行时动态地添加或者移除对象的职责,而无须修改原始类,使系统更加灵活且易于扩展。
- 避免类爆炸:适用继承来添加新功能会导致类的数量迅速增加,形成类爆炸,装饰模式通过组合而不是继承,会避免类爆炸。
- 单一职责和开闭原则:符合单一职责和开闭原则
- 缺点:
- 复杂性:引入很多小的装饰类,可能会增加代码复杂性。
- 运行时开销:每次装饰都需要创建一个新的装饰对象。
1.5 适用场景
- 功能扩展:当需要在不修改现有的对象,动态地添加功能时,可以适用装饰模式,利用组合的方式去增加功能。
- 避免类爆炸: 当需要为多个独立的对象添加相同或类似的功能时,装饰模式可以避免创建大量的子类来实现不同组合的功能。它允许你按需组合功能,而不是静态地继承。
二、外观模式
2.1 概念
外观模式(又称门面模式)是一种使用频率很高的设计模式,它通过引入一个外观角色来简化客户端与子系统之间的交互。为复杂的子系统调用提供了一个统一的入口,使子系统与客户端的耦合度降低。外观类将客户类与子系统的内部复杂性分隔开来,客户类只需要跟外观角色打交道,不需要与子系统内部的很多对象打交道。
定义:外观模式是一种为多个复杂的子系统提供一致的接口,而使这些子系统更容易被访问的模式,该模式对外有一个统一接口,外观角色不用关心内部子系统的具体细节。
2.2 模式结构
-
Facade(外观角色):它是客户端和子系统的中介,封装了子系统的复杂性,并提供了一个接口给客户端使用。
-
SubSystem(子系统角色):实现了子系统的功能,由多个模块组成,可以是一个类或者多个类。外观角色也是子系统角色的客户端类。
2.3 应用实例
设计一个DVD播放器系统,它由多个子系统组成,如音频、视频、界面等
-
SubSystem:子系统
public class Audio { public void On() { Console.WriteLine("Audio On"); } public void Off() { Console.WriteLine("Audio Off"); } } public class Video { public void On() { Console.WriteLine("Video On"); } public void Off() { Console.WriteLine("Viedo Off"); } } public class UIPanel { public void On() { Console.WriteLine("UIPanel On"); } public void Off() { Console.WriteLine("UIPanel Off"); } }
-
Facade:外观角色
public class MediaPlayerFacade { private Audio _audio; private Video _video; private UIPanel _panel; public MediaPlayerFacade() { _audio = new Audio(); _video = new Video(); _panel = new UIPanel(); } public void Play() { _audio.On(); _video.On(); _panel.On(); } public void Stop() { _audio.Off(); _video.Off(); _panel.Off(); } }
-
Client类:
public class Client { public void Main(string[] args) { MediaPlayerFacade mediaPlayerFacade = new MediaPlayerFacade(); mediaPlayerFacade.Play(); mediaPlayerFacade.Stop(); /* * Audio On * Video On * UIPanel On * Audio Off * Viedo Off * UIPanel Off */ } }
2.4 优缺点
- 优点:
- 符合迪米特法则:外观模式使用户不需要了解子系统内部情况,只与外观模式交互,降低了应用层与子系统之间的耦合度。
- 简化调用、层次控制:简化了复杂系统的调用过程,只需要与外观类交互即可,将客户端与子系统分层。
- 缺点:
- 不符合开闭原则:当需要增加新的子系统或移除现有系统时,可能需要修改外观类或者客户端代码,不够灵活。
- 可能导致系统过于复杂:过度使用外观模式可能增加系统中类的数量。
2.5 适用场景
- 对外提供简化接口:当需要向外部提供一个简化接口并隐藏内部复杂性时,如SDK、API、库等可以使用外观模式。
- 层次结构系统:在层次结构复杂的系统中,可以使用外观模式对客户端和子系统进行解耦分层。