写点什么

【愚公系列】2022 年 05 月 二十三种设计模式 (九)- 装饰者模式 (Decorator Pattern)

作者:愚公搬代码
  • 2022 年 5 月 09 日
  • 本文字数:2226 字

    阅读完需:约 7 分钟

前言

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。

一、装饰者模式(Decorator Pattern)

装饰者模式属于结构型模式,装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。


装饰者模式通过创建一个包装对象(wrapper),也就是用装饰来包裹真实的对象。

二、使用步骤

角色

1、抽象构件(Component)


给出一个抽象接口,以规范准备接收附加责任的对象;


2、具体构件(Concrete Component)


定义一个将要接收附加责任的类;


3、抽象装饰(Decorator)


持有一个构件(Component)对象的实例,并实现一个与抽象构件接口一致的接口;


4、具体装饰(Concrete Decorator)


负责给构件对象添加上附加的责任。

示例


命名空间 DecoratorPattern 中包含汽车 Car 类、玛莎拉蒂 Maserati 类、法拉利 Fabbrica 类、酷汽车 CoolCar 类、汽车车贴 Paster 类和汽车遮阳挡 Visor 类。本示例通过使用装饰者模式为汽车进行一次简单的外观装饰。


public abstract class Car {
public string Name { get; set; }
public abstract void StartUp();
}
复制代码


汽车基类 Car,充当抽象构件。


public class Fabbrica : Car {     public Fabbrica() {        Name = "Fabbrica";    }     public override void StartUp() {        Console.WriteLine($"{Name} is starting!");    } }
复制代码


法拉利 Fabbrica 类,充当具体构件。


public class Maserati : Car {     public Maserati() {        Name = "Maserati";    }     public override void StartUp() {        Console.WriteLine($"{Name} is starting!");    } }
复制代码


玛莎拉蒂 Maserati 类,充当具体构件。


public abstract class CoolCar : Car {     protected Car _car = null;     public CoolCar(Car car) {        _car = car;    }     public override void StartUp() {        Console.WriteLine($"{_car.Name} is starting!");    } }
复制代码


酷汽车 CoolCar 类,充当抽象装饰。


public class Paster : CoolCar {     public Paster(Car car) : base(car) {     }     public override void StartUp() {        SetPaster();        base.StartUp();    }     private void SetPaster() {        Console.WriteLine($"Set paster to {_car.Name}!");    } }
复制代码


汽车车贴 Paster 类,通过继承 CoolCar 类,为对汽车进行装饰提供了可能。


public class Visor : CoolCar {     public Visor(Car car) : base(car) {     }     public override void StartUp() {        SetVisor();        base.StartUp();    }     private void SetVisor() {        Console.WriteLine($"Set visor to {_car.Name}!");    } }
复制代码


汽车遮阳挡 Visor 类,通过继承 CoolCar 类,为对汽车进行装饰提供了可能。


public class Program {
private const string LINE_SPLIT = "-------------------------";
private static Car _car = null;
private static CoolCar _coolCar = null;
public static void Main(string[] args) { _car = new Maserati();
_coolCar = new Visor(_car); _coolCar.StartUp(); Console.WriteLine(LINE_SPLIT);
_car = new Fabbrica();
_coolCar = new Paster(_car); _coolCar.StartUp(); Console.WriteLine(LINE_SPLIT);
Console.ReadKey(); }
}
复制代码


以上是调用方的代码,以下是这个案例的输出结果:


Set visor to Maserati!Maserati is starting!-------------------------Set paster to Fabbrica!Fabbrica is starting!-------------------------
复制代码


<hr style=" border:solid; width:100px; height:1px;" color=#000000 size=1">

总结

优点

1、装饰者模式与继承关系的目的都是要扩展对象的功能,但是装饰者模式可以提供比继承更多的灵活性;2、通过使用不同的具体装饰类以及这些装饰类的排列组合,开发者可以创造出很多不同行为的组合。

缺点

1、这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性;2、装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂;3、装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变 Component 接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。

使用场景

1、需要扩展一个类的功能,或给一个类添加附加职责;2、需要动态的给一个对象添加功能,这些功能可以再动态的撤销;3、需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实;4、当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸式增长。另一种情况可能是因为类定义被隐藏,或类定义不能用

发布于: 刚刚阅读数: 2
用户头像

还未添加个人签名 2022.03.01 加入

该博客包括:.NET、Java、前端、IOS、Android、鸿蒙、Linux、物联网、网络安全、python、大数据等相关使用及进阶知识。查看博客过程中,如有任何问题,皆可随时沟通。

评论

发布
暂无评论
【愚公系列】2022年05月 二十三种设计模式(九)-装饰者模式(Decorator Pattern)_5月月更_愚公搬代码_InfoQ写作社区