C# 设计模式(9)装饰者
参考:head first 设计模式
参考:https://www.cnblogs.com/zhili/p/DecoratorPattern.html
装饰者与桥接区别
桥接模式:必须由一方使用抽象类,持有使用接口的一方
装饰者模式:装饰者模式是实现接口,桥接模式是以组合的方式持有接口
应用场景
开发中我们经常想要对一类对象添加不同的功能。例如要给手机添加贴膜,挂件,外壳等
/如果此时利用继承来实现的话,就需要定义无数的类,如StickerPhone贴膜是手机类,
AccessoriesPhone挂件类等,这样会导致子类爆炸,解决这个问题我们可以用装饰者模式来动态地给一个对象添加额外的职责,装饰者模式以对客户透明的方式动态地给一个对象附加上更多的责任,装饰者模式相比生成子类,可以更加灵活地增加功能
1.需要扩展一个类的功能或者给一个类增加附加责任
2.需要动态的给一个对象增加功能,这些功能可以动态的撤销
3.需要增加由一些基本功能的排列组合而产生非常大量的功能
结构
装饰者模式采对象组合而非继承的方式实现了在运行时动态地扩展对象功能的能力,而且可以根据需要扩展多个功能,避免了单独使用继承带来的“灵活性差”和“多子类衍生问题”,同时它能很好地符合面向对象设计原则中“优先使用对象组合而非继承”和“开放-封闭”原则。
抽象构件:Phone角色:给出一个抽象接口以规范准备接受附加责任的对象
具体构件:ApplePhone角色:定义一个将要接受附加责任的类
装饰角色:Decorator角色:持有一个构件Component对象的实例,并定义一个与抽象构件接口一致的接口
具体装饰:Sticke和Accessories角色:负责给构件对象“贴上”附加的责任
图例
特点
优点:
装饰者模式和继承的目的都是扩展对象的功能,但装饰者模式比继承更加灵活,通过使用不同的具体装饰类以及这些类的排列组合,设计师可以创造出很多不同行为的组合,扩展性要好些。
缺点:
导致设计中出现小对象,过度使用会让程序复杂。并且更多的对象导致查错困难。
系统自带
.net自带的System.IO.Stream
Stream>GzipStream,CryptoStream,BufferedStream,FileStream,MemoryStream,NetWorkStream
BufferedStream,CryptoStream,GZIpStream其实就是两个具体装饰类,这里的装饰者模式省掉了抽象装饰器角色(Decorator)。
System.IO.MemoryStream ms = new System.IO.MemoryStream(new byte[] { 1, 2, 3 }) ;
System.IO.BufferedStream bs = new System.IO.BufferedStream(ms);
System.IO.Compression.GZipStream gs = new System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Compress, true);
代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DesignPattern
{
public class DecoratorPattern
{
public static void main()
{
//买个新手机
Phone p = new ApplePhone();
//想贴膜了
Decorator d = new Sticker(p);
d.Print();
//想要挂件了
Decorator dd = new Accessories(p);
dd.Print();
//现在我同事有贴膜和挂件了
Sticker sticker = new Sticker(p);
Accessories a = new Accessories(sticker);
a.Print();
//可以看出,客户端可以动态地将手机配件增加到手机上
//如果需要额外添加手机壳时,此时只需要添加一个继承Decorator的手机壳类
//装饰者模式的扩展性也非常好
}
/// <summary>
/// 手机抽象类,即装饰者模式中的抽象组件类
/// </summary>
public abstract class Phone
{
public abstract void Print();
}
/// <summary>
/// 苹果手机 即装饰者模式中的具体组件类
/// </summary>
public class ApplePhone : Phone
{
public override void Print()
{
Console.WriteLine("开始 苹果手机");
}
}
/// <summary>
/// 装饰抽象类,要让装饰完全取代抽象组件,所以必须继承自Phone
/// </summary>
public abstract class Decorator : Phone
{
private Phone phone;
public Decorator(Phone p)
{
this.phone = p;
}
public override void Print()
{
phone?.Print();
}
}
/// <summary>
/// 贴膜 即具体装饰者
/// </summary>
public class Sticker : Decorator
{
public Sticker(Phone p)
: base(p)
{
}
public override void Print()
{
base.Print();
//添加新的行为
AddSticker();
}
public void AddSticker()
{
Console.WriteLine("现在手机有贴膜了");
}
}
/// <summary>
/// 挂件 具体装饰者
/// </summary>
public class Accessories : Decorator
{
public Accessories(Phone p) : base(p) { }
public override void Print()
{
base.Print();
AddAccessories();
}
public void AddAccessories()
{
Console.WriteLine("现在手机有挂件了");
}
}
}
}
相关文章
- C#设计模式导论
- C#中AssemblyInfo.cs文件详解
- c# mysql executenonquery_C#与数据库访问技术之ExecuteNonQuery方法
- C#设计模式——(创建型-抽象工厂设计模式)
- C#设计模式——(创建型-原型设计模式)
- C#设计模式——(结构型-外观设计模式)
- C#设计模式——(结构型-桥接设计模式)
- C#设计模式——(结构型-享元设计模式)
- c# 多线程并发-金三银四面试:C#.NET面试题高级篇2-多线程
- 开心档之C# 匿名方法
- 从C中用MSSQL创建触发器(mssql触发器c#)
- C#利用com操作excel释放进程的解决方法
- C#撒列实现关键字过滤的实例
- 深入C#字符串和享元(Flyweight)模式的使用分析
- C#泛型相关讲解
- C#调用Java类的实现方法
- 通过C#动态生成图书信息XML文件
- C#波形图控件制作示例程序
- jssubstr,substring与javasubstring和C#substring的区别解析
- c#的datatable转list示例
- 浅谈c#设计模式之单一原则
- C#特性匿名类型与隐式类型局部变量使用介绍
- C#语音识别用法实例
- C#虚方法的声明和使用实例教程
- C#中把字符串String转换为整型Int的小例子
- C++与C#互调dll的实现步骤
- C#使用ping命令的两个例子