23种设计模式之装饰器模式(Decorator Pattern)

Posted dewumu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了23种设计模式之装饰器模式(Decorator Pattern)相关的知识,希望对你有一定的参考价值。

 装饰器模式(Decorator Pattern)

允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

通过采用组合、而非继承的手法,Decorator模式实现了在运行时动态地扩展对象功能的能力,而且可以
根据需要扩展多个功能。避免了单独使用继承带来的“灵活性差"和"多子类衍生问题"。

优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能

缺点:多层装饰比较复杂

使用场景: 1、扩展一个类的功能。 2、动态增加功能,动态撤销   例如游戏装备,以及各层vip,商场的多重优惠等等

应用实例:不论一幅画有没有画框都可以挂在墙上,但是通常都是有画框的,并且实际上是画框被挂在墙上。在挂在墙上之前,画可以被蒙上玻璃,装到框子里;这时画、玻璃和画框形成了一个物体

技术图片

装饰器模式主要组成部分

Component:定义一个对象接口,可以给这些对象动态地添加职责

ConcreteComponent:定义一个对象,可以给这个对象添加一些职责

Decorator:维持一个指向Component的指针,并定义一个与Component接口一致的接口

ConcreteDecorator:负责向ConcreteComponent添加功能

 

假如我们需要为游戏中开发一种坦克,除了各种不同型号的坦克外,我们还希望在不同场合中为其增加以下一种或多种功能;比如红外线夜视功能,比如水陆两栖功能,比如卫星定位功能等等

按类继承的作法如下:

技术图片
1      //抽象坦克
2      public abstract class Tank
3      
4         public abstract void Shot();
5         public abstract void Run();
6      
View Code

各种型号:

技术图片
 1     //T50型号
 2     public class T50:Tank
 3      
 4         public override void Shot()
 5          
 6             Console.WriteLine("T50坦克平均每秒射击5发子弹");
 7          
 8          public override void Run()
 9         
10              Console.WriteLine("T50坦克平均每时运行30公里");
11          
12      
View Code
技术图片
 1      //T75型号 
 2      public class T75 : Tank
 3      
 4          public override void Shot()
 5          
 6              Console.WriteLine("T75坦克平均每秒射击10发子弹");
 7          
 8          public override void Run()
 9          
10              Console.WriteLine("T75坦克平均每时运行35公里");
11          
12      
View Code
技术图片
 1      //T90型号  
 2      public class T90 :Tank
 3      
 4         public override void Shot()
 5         
 6             Console.WriteLine("T90坦克平均每秒射击10发子弹");
 7          
 8          public override void Run()
 9          
10              Console.WriteLine("T90坦克平均每时运行40公里");
11          
12      
View Code

各种不同功能的组合:比如IA具有红外功能接口、IB具有水陆两栖功能接口、IC具有卫星定位功能接口。

技术图片
 1  //T50坦克各种功能的组合
 2  public class T50A:T50,IA
 3  
 4    //具有红外功能
 5  
 6  public class T50B:T50,IB
 7  
 8   //具有水陆两栖功能
 9  
10  public class T50C:T50,IC
11  
12  
13  
14  public class T50AB:T50,IA,IB
15  
16  public class T50AC:T50,IA,IC
17  
18  public class T50BC:T50,IB,IC
19  
20  public class T50ABC:T50,IA,IB,IC
21 
View Code
技术图片
 1      //T75各种不同型号坦克各种功能的组合
 2    public class T75A:T75,IA
 3    
 4      //具有红外功能
 5    
 6    public class T75B:T75,IB
 7    
 8     //具有水陆两栖功能
 9    
10   public class T75C:T75,IC
11   
12     //具有卫星定位功能
13   
14   public class T75AB:T75,IA,IB
15   
16    //具有红外、水陆两栖功能
17  
18   public class T75AC:T75,IA,IC
19  
20    //具有红外、卫星定位功能
21  
22   public class T75BC:T75,IB,IC
23   
24   //具有水陆两栖、卫星定位功能
25  
26   public class T75ABC:T75,IA,IB,IC
27   
28    //具有红外、水陆两栖、卫星定位功能
29  
View Code
技术图片
 1      //T90各种不同型号坦克各种功能的组合
 2    public class T90A:T90,IA
 3    
 4      //具有红外功能
 5    
 6    public class T90B:T90,IB
 7    
 8     //具有水陆两栖功能
 9    
10   public class T90C:T90,IC
11   
12     //具有卫星定位功能
13   
14   public class T90AB:T90,IA,IB
15   
16    //具有红外、水陆两栖功能
17  
18   public class T90AC:T90,IA,IC
19   
20    //具有红外、卫星定位功能
21  
22   public class T90BC:T90,IB,IC
23   
24   //具有水陆两栖、卫星定位功能
25  
26   public class T90ABC:T90,IA,IB,IC
27   
28    //具有红外、水陆两栖、卫星定位功能
29  
View Code

由此可见,如果用类继承实现,子类会爆炸式地增长

装饰器模式实现代码:

技术图片
1 namespace Decorator
2  
3    public abstract class Tank
4      
5         public abstract void Shot();
6         public abstract void Run();
7      
8  
View Code
技术图片
 1      public class T50:Tank
 2      
 3          public override void Shot()
 4          
 5              Console.WriteLine("T50坦克平均每秒射击5发子弹");
 6          
 7          public override void Run()
 8          
 9             Console.WriteLine("T50坦克平均每时运行30公里");
10          
11      
View Code
技术图片
 1      public class T75 : Tank
 2      
 3          public override void Shot()
 4          
 5              Console.WriteLine("T75坦克平均每秒射击10发子弹");
 6          
 7          public override void Run()
 8          
 9              Console.WriteLine("T75坦克平均每时运行35公里");
10          
11      
View Code
技术图片
 1      public class T90 :Tank
 2      
 3          public override void Shot()
 4          
 5              Console.WriteLine("T90坦克平均每秒射击10发子弹");
 6          
 7          public override void Run()
 8          
 9              Console.WriteLine("T90坦克平均每时运行40公里");
10          
11      
View Code
技术图片
 1     public abstract class Decorator :Tank //Do As 接口继承 非实现继承
 2      
 3         private Tank tank; //Has a  对象组合
 4         public Decorator(Tank tank)
 5         
 6             this.tank = tank;
 7         
 8         public override void Shot()
 9         
10             tank.Shot();
11         
12         public override void Run()
13         
14             tank.Run();
15         
16      
View Code
技术图片
 1     public class DecoratorA :Decorator
 2     
 3         public DecoratorA(Tank tank) : base(tank)
 4         
 5         
 6        public override void Shot()
 7        
 8           //Do some extension //功能扩展 且有红外功能
 9           base.Shot();
10        
11        public override void Run()
12        
13  
14          base.Run();
15        
16      
View Code
技术图片
 1     public class DecoratorB :Decorator
 2      
 3        public DecoratorB(Tank tank) : base(tank)
 4         
 5         
 6        public override void Shot()
 7        
 8           //Do some extension //功能扩展 且有水陆两栖功能
 9           base.Shot();
10        
11       public override void Run()
12       
13         base.Run();
14       
15     
View Code
技术图片
 1     public class DecoratorC :Decorator
 2      
 3         public DecoratorC(Tank tank) : base(tank)
 4         
 5        
 6        public override void Shot()
 7        
 8          //Do some extension //功能扩展 且有卫星定位功能
 9           base.Shot();
10        
11        public override void Run()
12        
13  
14          base.Run();
15         
16           
17     
View Code

前端调用:

技术图片
1          static void Main(string[] args)
2          
3              Tank tank = new T50();
4              DecoratorA da = new DecoratorA(tank); //且有红外功能
5              DecoratorB db = new DecoratorB(da);   //且有红外和水陆两栖功能
6             DecoratorC dc = new DecoratorC(db);   //且有红外、水陆两栖、卫星定们三种功能
7              dc.Shot();
8              dc.Run();
9          
View Code

Decorator在.NET(Stream)中的应用:

BufferedStream和CryptoStream其实就是两个包装类,这里的Decorator模式省略了抽象装饰角色(Decorator),示例代码如下:

技术图片
 1      public static void Main(string[] args)
 2      
 3          MemoryStream ms =
 4              new MemoryStream(new byte[]  100,456,864,222,567);
 5          //扩展了缓冲的功能
 6          BufferedStream buff = new BufferedStream(ms);
 7  
 8          //扩展了缓冲,加密的功能
 9           CryptoStream crypto = new CryptoStream(buff);
10      
View Code
技术图片
 1    public sealed class BufferedStream : Stream
 2   
 3     // Methods
 4      private BufferedStream();
 5      public BufferedStream(Stream stream);
 6      public BufferedStream(Stream stream, int bufferSize);
 7      // Fields
 8      private int _bufferSize;
 9      private Stream _s;
10    
View Code

通过反编译,可以看到BufferedStream类的代码(只列出部分),它是继承于Stream类

本文参考文档:

https://www.cnblogs.com/abcdwxc/archive/2007/09/06/884495.html

https://www.runoob.com/design-pattern/decorator-pattern.html

https://www.cnblogs.com/banluduxing/p/9152453.html

以上是关于23种设计模式之装饰器模式(Decorator Pattern)的主要内容,如果未能解决你的问题,请参考以下文章

一文弄懂23种设计模式之装饰器模式

设计模式之装饰器模式(decorator pattern)

设计模式入门之装饰器模式Decorator

C++之装饰(decorator)模式

23种设计模式——装饰模式单一职责

二十三种设计模式之装饰器模式