23装饰模式(Decorator Pattern)

子类复子类,子类何其多

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

1  //抽象坦克
2  public abstract class Tank
3     {
4        public abstract void Shot();
5        public abstract void Run();
6     }

各种型号:

 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     }

 

 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     }

 

 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     }

各种不同功能的组合:比如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 {}
18 public class T50AC:T50,IA,IC
19 {}
20 public class T50BC:T50,IB,IC
21 {}
22 public class T50ABC:T50,IA,IB,IC
23 {}

 

 1 
 2   //T75各种不同型号坦克各种功能的组合
 3   public class T75A:T75,IA
 4   {
 5     //具有红外功能
 6   }
 7   public class T75B:T75,IB
 8   {
 9    //具有水陆两栖功能
10   }
11  public class T75C:T75,IC
12  {
13    //具有卫星定位功能
14  }
15  public class T75AB:T75,IA,IB
16  {
17   //具有红外、水陆两栖功能
18 }
19  public class T75AC:T75,IA,IC
20  {
21   //具有红外、卫星定位功能
22 }
23  public class T75BC:T75,IB,IC
24  {
25  //具有水陆两栖、卫星定位功能
26 }
27  public class T75ABC:T75,IA,IB,IC
28  {
29   //具有红外、水陆两栖、卫星定位功能
30 }

 

 1 
 2   //T90各种不同型号坦克各种功能的组合
 3   public class T90A:T90,IA
 4   {
 5     //具有红外功能
 6   }
 7   public class T90B:T90,IB
 8   {
 9    //具有水陆两栖功能
10   }
11  public class T90C:T90,IC
12  {
13    //具有卫星定位功能
14  }
15  public class T90AB:T90,IA,IB
16  {
17   //具有红外、水陆两栖功能
18 }
19  public class T90AC:T90,IA,IC
20  {
21   //具有红外、卫星定位功能
22 }
23  public class T90BC:T90,IB,IC
24  {
25  //具有水陆两栖、卫星定位功能
26 }
27  public class T90ABC:T90,IA,IB,IC
28  {
29   //具有红外、水陆两栖、卫星定位功能
30 }

由此可见,如果用类继承实现,子类会爆炸式地增长。
动机(Motivate):
    上述描述的问题根源在于我们“过度地使用了继承来扩展对象的功能”,由于继承为类型引入的静态物质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能组合)会导致更多子类的膨胀(多继承)。
   如何使“对象功能的扩展”能够根据需要来动态地实现?同时避免“扩展功能的增多”带来的子类膨胀问题?从而使得任何“功能扩展变化”所导致的影响将为最低?
意图(Intent):
    动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。
                                                              ------《设计模式》GOF
结构图(Struct):
                 



生活中的例子:
                           

适用性:
    需要扩展一个类的功能,或给一个类增加附加责任。

    需要动态地给一个对象增加功能,这些功能可以再动态地撤销。

    需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变得不现实。

实现代码:
    

1 namespace Decorator
2 {
3   public abstract class Tank
4     {
5        public abstract void Shot();
6        public abstract void Run();
7     }
8 }

 

 1 namespace Decorator
 2 {
 3    public class T50:Tank
 4     {
 5         public override void Shot()
 6         {
 7             Console.WriteLine("T50坦克平均每秒射击5发子弹");
 8         }
 9         public override void Run()
10         {
11             Console.WriteLine("T50坦克平均每时运行30公里");
12         }
13     }
14 }

 

 1 namespace Decorator
 2 {
 3     public class T75 : Tank
 4     {
 5         public override void Shot()
 6         {
 7             Console.WriteLine("T75坦克平均每秒射击10发子弹");
 8         }
 9         public override void Run()
10         {
11             Console.WriteLine("T75坦克平均每时运行35公里");
12         }
13     }
14 }

 

 1 namespace Decorator
 2 {
 3     public class T90 :Tank
 4     {
 5         public override void Shot()
 6         {
 7             Console.WriteLine("T90坦克平均每秒射击10发子弹");
 8         }
 9         public override void Run()
10         {
11             Console.WriteLine("T90坦克平均每时运行40公里");
12         }
13     }
14 }

 

 1 namespace Decorator
 2 {
 3    public abstract class Decorator :Tank //Do As 接口继承 非实现继承
 4     {
 5        private Tank tank; //Has a  对象组合
 6        public Decorator(Tank tank)
 7        {
 8            this.tank = tank;
 9        }
10        public override void Shot()
11        {
12            tank.Shot();
13        }
14        public override void Run()
15        {
16            tank.Run();
17        }
18     }
19 }
20 

 

 1 
 2 namespace Decorator
 3 {
 4    public class DecoratorA :Decorator
 5     {
 6        public DecoratorA(Tank tank) : base(tank)
 7        {
 8        }
 9       public override void Shot()
10       {
11          //Do some extension //功能扩展 且有红外功能
12           base.Shot();
13       }
14     public override void Run()
15     {
16 
17         base.Run();
18     }
19     }
20 }

 

 1 namespace Decorator
 2 {
 3     public class DecoratorB :Decorator
 4     {
 5       public DecoratorB(Tank tank) : base(tank)
 6        {
 7        }
 8       public override void Shot()
 9       {
10          //Do some extension //功能扩展 且有水陆两栖功能
11          base.Shot();
12       }
13     public override void Run()
14     {
15 
16         base.Run();
17     }
18    }    
19 }
20 

 

 1 namespace Decorator
 2 {
 3     public class DecoratorC :Decorator
 4     {
 5        public DecoratorC(Tank tank) : base(tank)
 6        {
 7        }
 8       public override void Shot()
 9       {
10          //Do some extension //功能扩展 且有卫星定位功能
11          base.Shot();
12       }
13     public override void Run()
14     {
15 
16         base.Run();
17     } 
18         
19    }
20 }

 

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


Decorator模式的几个要点:
    通过采用组合、而非继承的手法,Decorator模式实现了在运行时动态地扩展对象功能的能力,而且可以
根据需要扩展多个功能。避免了单独使用继承带来的“灵活性差"和"多子类衍生问题"。
    Component类在Decorator模式中充当抽象接口的角色,不应该去实现具体的行为。而且Decorator类对于Component类应该透明---换言之Component类无需知道Decorator类,Decorator类是从外部来扩展Component类的功能。
    Decorator类在接口上表现为is-a Component的继承关系,即Decorator类继承了Component类所且有的接口。但在实现上又表现has a Component的组合关系,即Decorator类又使用了另外一个Component类。我们可以使用一个或者多个Decorator对象来“装饰”一个Component对象,且装饰后的对象仍然是一个Component对象。
    Decorator模式并非解决”多子类衍生的多继承“问题,Decorator模式应用的要点在于解决“主体
类在多个方向上的扩展功能”------是为“装饰”的含义。

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

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

 1 class Program
 2 
 3 {
 4 
 5     public static void Main(string[] args)
 6 
 7     {
 8 
 9         MemoryStream ms =
10 
11             new MemoryStream(new byte[] { 100,456,864,222,567});
12 
13  
14 
15         //扩展了缓冲的功能
16 
17         BufferedStream buff = new BufferedStream(ms);
18 
19  
20 
21         //扩展了缓冲,加密的功能
22 
23         CryptoStream crypto = new CryptoStream(buff);
24 
25     }
26 
27 }


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

 1 public sealed class BufferedStream : Stream
 2 
 3 {
 4 
 5     // Methods
 6 
 7     private BufferedStream();
 8 
 9     public BufferedStream(Stream stream);
10 
11     public BufferedStream(Stream stream, int bufferSize);
12 
13     // Fields
14 
15     private int _bufferSize;
16 
17     private Stream _s;
18 
19 }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/438650.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

gb2312编码在线转换_python基础学习—04字符串与编码

点击上方蓝字关注我们不迷路!字符串与编码一、了解计算机编码1.1 编码定义:将信息从一种形式转换为另外一种形式的过程叫做编码,即信息转换过程举例:信息加密解密、语言翻译1.2 计算机编码定义:将计算机可读信息转换…

25外观模式(Facade Pattern)

动机(Motivate): 在软件开发系统中,客户程序经常会与复杂系统的内部子系统之间产生耦合,而导致客户程序随着子系统的变化而变化。那么如何简化客户程序与子系统之间的交互接口?如何将复杂系统的内部子系统与客户程序之间的依赖解耦&#…

mysql mybatis类型对应_Mybatis与数据库的类型对应

Mybatis与数据库的类型对应由于业务的改变,在首次存入数据库时某些int属性并没有赋值,于是默认值就开始污染数据库了。java实体属性对应mysql和SQL Server 和Oracle 数据类型对应1:Java数据类型与MySql数据类型对照表*对于bolb,一…

26享元模式(Flyweight Pattern)

面向对象的代价 面向对象很好地解决了系统抽象性的问题,同时在大多数情况下,也不会损及系统的性能。但是,在 某些特殊的应用中下,由于对象的数量太大,采用面向对象会给系统带来难以承受的内存开销。比如: 图形应用…

mysql一个事务多个log_MySQL识别一个binlog中的一个事物

MySQL测试版本5.7.14设置GTID_MODEONON(3): Both new and replicated transactions must be GTID transactions(生成的是GTID事物,slave也只能应用GTID事物)设置binlog格式为row模式做如下操作mysql> insert into test values(1,2);Query OK, 1 row affected (0.…

go for 循环遍历数组并排序_10. Go语言流程控制:for 循环

本文原文:http://golang.iswbm.comGithub:http://github.com/iswbm/GolangCodingTimeGo里的流程控制方法还是挺丰富,整理了下有如下这么多种:if - else 条件语句switch - case 选择语句for - range 循环语句goto 无条件跳转语句de…

27代理模式(Proxy Pattern)

直接与间接: 人们对复杂的软件系统常有一种处理手法,即增加一层间接层,从而对系统获得一种更为灵活、 满足特定需求的解决方案。 …

31模板方法(Template Method)

无处不在的Template Method 如果你只想掌握一种设计模式,那么它就是Template Method! 动机(Motivate): 变化 -----是软件设计的永恒主题,如何管理变化带来的复杂性?设计模式的艺术性和复杂度就在于如何 分析,并发现系统中…

bat 脚本清空窗口内容_tomcat9.0启动脚本startup.bat的分析

1、 Apache Tomcat的下载和安装从Apache官网https://tomcat.apache.org/可以下载各种版本的tomcat软件,下载的文件格式可以是zip/tar.gz/exe形式的。如下图所示,在64位windows中使用tomcat,我们可以下载"64-bit Windows.zip",直接解…

33迭代器模式(Iterator Pattern)

动机(Motivate): 在软件构建过程中,集合对象内部结构常常变化各异。但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码透明地访问其中包含的元素;同时这种“透明遍历”也为“ 同一种算法在多种集合对象上进行操作…

32命令模式(Command Pattern)

耦合与变化: 耦合是软件不能抵御变化灾难的根本性原因。不仅实体对象与实体对象之间存在耦合关系,实体对象与行为操作之间也存在耦合关系。 动机(Mot…

34观察者模式(Observer Pattern)

动机(Motivate):在软件构建 过程中,我们需要为某些对象建立一种“通知依赖关系” --------一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密&#x…

36中介者模式(Mediator Pattern)

依赖关系的转化: 动机(Motivate): 在软件构建过程中,经常会出现多个对象互相关联交互的情况,对象之间常常会维持一种复杂的引用关系,如果遇到一些需求的更改,这种直接的引用关系将面临不断的变化。 在这种情况…

相似理论与模型试验_正交实验下的固液耦合相似材料研究

原标题:基于正交试验的固液耦合相似材料研究摘 要:为了研究矿井突水演化规律,通过正交试验研制出一种能同时满足固体力学与水理性的固液 耦合相似材料,该相似材料以河沙为骨料、水泥和大白粉为胶结剂、液体石蜡和淀粉为调节剂。采用 极差分析…

35解释器模式(Interpreter Pattern)

动机(Motivate): 在软件构建过程中,如果某一特定领域的问题比较复杂,类似的模式不断重复出现,如果使用普通的编程方式来实现将面临非常频繁的变化。 在这种情况下,将特定领域的问题表达为某种文法规则下的句子,…

37职责链模式(Chain of Responsibility Pattern)

动机(Motivate): 在软件构建过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能有一个接受者,如果显示指定,将必不可少地带来请求发送者与接受者的紧耦合。 如何使请求的发送者不需要指定具体的接受…

python3中format函数列表_Python3之字符串格式化format函数详解(上)

173.jpg概述在Python3中,字符串格式化操作通过format()方法或者fstring实现。而相比于老版的字符串格式化方式,format()方法拥有更多的功能,操作起来更加方便,可读性也更强。该函数将字符串当成一个模板,通过传入的参数…

38备忘录模式(Memento Pattern)

对象状态的回溯: 对象状态的变化无端,如何回溯/恢复对象在某个点的状态? 动机: 在软件构建过程中,某些对象的状态在转换过程中,可能由于某种需要,要求程序能够…

39策略模式(Strategy Pattern)

算法与对象的耦合: 对象可能经常需要使用多种不同的算法,但是如果变化频繁,会将类型变得脆弱... 动机: 在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将…

40访问者模式(Visitor Pattern)

类层次结构的变化: 类层次结构中可能经常由于引入新的操作,从而将类型变得脆弱... 动机: 在软件构建过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接…