一,装饰者模式(Decorator Pattern):装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。

二,在以上代码中我们是中国人是根本行为,我们给中国人装饰我会说英语,我会说日语和我会说英语我会说日语这三种行为,那按正常的理解来说,这是多态,那我们对People中的Say我们是不是需要有三种实现方法呢?三种还是比较好解决,但是如果我们有N种呢?难道我们要有N个实现类么?这时我们就可以使用装饰者模式。

1》我们抽象People这个类,还有抽象的Say方法方法,这时People就可以有多国人的实现,我们使用一种中国人,假设,这是我们现有的代码的,但根据需求,我们需要给中国人添加我会说英语,我会说日语和我会说英语我会说日语这三种行为,那该怎么办?根据以往想法,一般如下设计:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6.  
  7. namespace Demo
  8. {
  9. class Program
  10. {
  11. static void Main(string[] args)
  12. {
  13. People p = new Englist();
  14. p.Say();
  15. People p1 = new Jan();
  16. p1.Say();
  17. People p2 = new JE();
  18. p2.Say();
  19. }
  20. }
  21. public abstract class People
  22. {
  23. public abstract void Say();
  24. }
  25. public class Chinese : People
  26. {
  27. public override void Say()
  28. {
  29. Console.WriteLine("我是中国人");
  30. }
  31. }
  32. public class Englist : Chinese
  33. {
  34. public override void Say()
  35. {
  36. base.Say();
  37. Console.WriteLine("我是会说英语");
  38. }
  39. }
  40. public class Jan : Chinese
  41. {
  42. public override void Say()
  43. {
  44. base.Say();
  45. Console.WriteLine("我是会说日语");
  46. }
  47. }
  48. public class JE : Chinese
  49. {
  50. public override void Say()
  51. {
  52. base.Say();
  53. Console.WriteLine("我是会说英语和日语");
  54. }
  55. }
  56. }

2》然而我们如果还有N种装饰中国人,难道要写N个子类?但是明显是不合理的,这时我们该怎么对chinese扩展呢?我们使用装饰者模式看看,如下代码:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6.  
  7. namespace _8.装饰者模式
  8. {
  9. //装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。
  10. class Program
  11. {
  12. static void Main(string[] args)
  13. {
  14. People p = new Chinese(); //没有扩展的实现
  15.  
  16. Decorator d = new Englist(p); //将会说英语的扩展给中国人
  17. d.Say();
  18. Console.WriteLine("----------------------\n");
  19.  
  20. Decorator d1 = new Jan(p); //将会说日语的扩展给中国人
  21. d1.Say();
  22. Console.WriteLine("----------------------\n");
  23.  
  24. Englist e = new Englist(p); //将会说英语和日语的扩展给中国人,这里是装饰者模式的核心,当我们存在这里三种可能的组合时,正常逻辑可能是每一种都实现一次,这样就存在三个实现子类,但是如果可能组合有几十上百种怎么办,这时我们可以使用装饰者模式,在代码中,我们只是实现说英语和说日语的两种可能,但我们可以实现组合得出第三种可能,这样代码就可以减少很多。
  25. Jan j = new Jan(e);
  26. j.Say();
  27. }
  28. }
  29.  
  30. public abstract class People
  31. {
  32. public abstract void Say();
  33. }
  34. public class Chinese : People
  35. {
  36. public override void Say() //根本的行为
  37. {
  38. Console.Write("我是中国人");
  39. }
  40. }
  41.  
  42. public abstract class Decorator : People
  43. {
  44. public People people;
  45. public Decorator(People p)
  46. {
  47. this.people = p;
  48. }
  49.  
  50. public override void Say()
  51. {
  52. people.Say();
  53. }
  54. }
  55. public class Englist : Decorator
  56. {
  57. public Englist(People p)
  58. : base(p)
  59. {
  60. }
  61.  
  62. public override void Say()
  63. {
  64. base.Say();
  65.  
  66. // 添加新的行为,动态地扩展一个对象的功能
  67. SayEnglish();
  68. }
  69.  
  70. /// <summary>
  71. /// 新的行为方法
  72. /// </summary>
  73. public void SayEnglish()
  74. {
  75. Console.WriteLine("我会说英语");
  76. }
  77. }
  78.  
  79. public class Jan : Decorator
  80. {
  81. public Jan(People p)
  82. : base(p)
  83. {
  84. }
  85.  
  86. public override void Say()
  87. {
  88. base.Say();
  89.  
  90. // 添加新的行为,动态地扩展一个对象的功能
  91. SayJan();
  92. }
  93.  
  94. /// <summary>
  95. /// 新的行为方法
  96. /// </summary>
  97. public void SayJan()
  98. {
  99. Console.WriteLine("我会说日语");
  100. }
  101. }
  102. }

两个代码对比,我们是不是发现少了一个子类的实现?,这样也减少了代码量。

3》但为什么下面代码可以实现两种组合?我们来理清点思路

  1. Englist e = new Englist(p);
  2. Jan j = new Jan(e);
  3. j.Say();

在上文中,我们的Englist 是继承Decorator而构造变量是People类型,但我们实例Englist 时,我们也传入了一个抽象people接收Chinese创建的中国人实例的变量进来,然后传给Englist ,而此时,人的对象已经传给Englist ,而Englist继承decorator,同时decorator继承people,我们重写Say()并调用的中国人的实现的方法Say()和调用SayEnglist(),这样我们就可以给原本的中国人装饰上说英语这一行为,如下代码:

  1.      public override void Say()
  2. {
  3. base.Say();
  4.  
  5. // 添加新的行为,动态地扩展一个对象的功能
  6. SayEnglist();
  7. }

4》那我们要同时说英语的日语呢?

根据3》中我么可以知道3中的Say方法代码已经综合了说英文,我们的思路是不是可以说,重写英语的Say(),调用英语的Say()和调用说日语的方法SayJan()就可以了?而不是说实现多一个子类。那为什么下面这句代码可以实现呢?综合了两种说话的行为呢?

  1. Jan j = new Jan(e);

我们来理解下,在上文我们实例的英语已经重写了Say的方法,而此时的Say()是已经包含了说英语的功能,同时Englist继承的父类最根本的就是people,根据继承的原则,我们是不是可以将Englist对象传给people,这里我们在看看Jan内重写Say()方法,并调用说日语的方法,这时不就可以同时给中国人添加两种行为了么

5》相对于同一个具体物件装饰器

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6.  
  7. namespace _08.装饰者模式
  8. {
  9. /// <summary>
  10. /// 装饰者模式属于结构型模式,装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。
  11. /// 装饰者模式通过创建一个包装对象(wrapper),也就是用装饰来包裹真实的对象。
  12. /// </summary>
  13. class Program
  14. {
  15. static void Main(string[] args)
  16. {
  17. People p = new China();
  18. p = new PeopleDecorator(p);
  19. p = new Chinese(p);
  20. p = new Englist(p);
  21. p.DoSome();
  22. }
  23. }
  24. /// <summary>
  25. /// People充当抽象构件。
  26. /// </summary>
  27. public abstract class People
  28. {
  29. public abstract void DoSome();
  30. }
  31. /// <summary>
  32. /// China充当具体构件
  33. /// </summary>
  34. public class China: People
  35. {
  36. public override void DoSome()
  37. {
  38. Console.WriteLine("我是中国人!!!");
  39. }
  40. }
  41. /// <summary>
  42. /// 抽象装饰(Decorator)
  43. /// </summary>
  44. public class PeopleDecorator : People
  45. {
  46. private People _people = null;
  47. public PeopleDecorator(People people)
  48. {
  49. this._people = people;
  50. }
  51. public override void DoSome()
  52. {
  53. _people.DoSome();
  54. }
  55. }
  56. /// <summary>
  57. /// 具体装饰(Concrete Decorator)
  58. /// </summary>
  59. public class Chinese : PeopleDecorator
  60. {
  61. private People _people = null;
  62. public Chinese(People people) : base(people)
  63. {
  64. this._people = people;
  65. }
  66. public override void DoSome()
  67. {
  68. _people.DoSome();
  69. Console.WriteLine("我说中文");
  70. }
  71. }
  72. /// <summary>
  73. /// 具体装饰(Concrete Decorator)
  74. /// </summary>
  75. public class Englist : Chinese
  76. {
  77. private People _people = null;
  78. public Englist(People people) : base(people)
  79. {
  80. this._people = people;
  81. }
  82. public override void DoSome()
  83. {
  84. _people.DoSome();
  85. Console.WriteLine("我说英语");
  86. }
  87. }
  88. }

C#设计模式:装饰者模式(Decorator Pattern)的更多相关文章

  1. 浅谈设计模式--装饰者模式(Decorator Pattern)

    挖了设计模式这个坑,得继续填上.继续设计模式之路.这次讨论的模式,是 装饰者模式(Decorator Pattern) 装饰者模式,有时也叫包装者(Wrapper),主要用于静态或动态地为一个特定的对 ...

  2. 设计模式 - 装饰者模式(Decorator Pattern) Java的IO类 用法

    装饰者模式(Decorator Pattern) Java的IO类 用法 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26716 ...

  3. 设计模式 - 装饰者模式(Decorator Pattern) 具体解释

    装饰者模式(Decorator Pattern) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26707033 装饰者 ...

  4. C#设计模式——装饰者模式(Decorator Pattern)

    一.例子在软件开发中,我们往往会想要给某一类对象增加不同的功能.比如要给汽车增加ESP.天窗或者定速巡航.如果利用继承来实现,就需要定义无数的类,Car,ESPCar,CCSCar,SunRoofCa ...

  5. 设计模式学习--装饰者模式(Decorator Pattern)

    概念: 装饰者模式(Decorator Pattern): 动态地将功能添加到对象,相比生成子类更灵活,更富有弹性. 解决方案: 装饰者模式的重点是对象的类型,装饰者对象必须有着相同的接口,也也就是有 ...

  6. 大话设计模式--装饰者模式 Decorator -- C++实现实例

    1.装饰者模式 Decorator 动态地给一个对象添加一个额外的职责, 就添加功能来说, 装饰模式比生成子类更为灵活. 每个装饰对象的实现和如何使用这个对象分离,  每个装饰对象只关心自己的功能,不 ...

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

    装饰器模式(Decorator Pattern) 允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰类,用来包 ...

  8. 设计模式(三):“花瓶+鲜花”中的装饰者模式(Decorator Pattern)

    在前两篇博客中详细的介绍了"策略模式"和“观察者模式”,今天我们就通过花瓶与鲜花的例子来类比一下“装饰模式”(Decorator Pattern).在“装饰模式”中很好的提现了开放 ...

  9. C#设计模式之装饰者模式(Decorator Pattern)

    1.概述 装饰者模式,英文名叫做Decorator Pattern.装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象. 2 ...

  10. Android设计模式之中的一个个样例让你彻底明确装饰者模式(Decorator Pattern)

    导读 这篇文章中我不会使用概念性文字来说明装饰者模式.由于通常概念性的问题都非常抽象.非常难懂.使得读者非常难明确究竟为什么要使用这样的设计模式.我们设计模式的诞生,肯定是前辈们在设计程序的时候遇到了 ...

随机推荐

  1. Nginx 的总结

    目录 Nginx 的产生 Nginx 的用武之地 Web 服务器对比 Nginx 的产生 Nginx 同 Apache 一样都是一种 Web 服务器.基于 REST 架构风格,以统一资源描述符(Uni ...

  2. 【改】utf-8 的去掉BOM的方法

    最近在测试中发现,linux系统中导出的文件,有记事本打开另存为或者保存后,再次导入进linux系统,发现失败了,对比文件内容,没发现区别,打开二进制文件对比发现,文件头部多了三个字符:EF BB B ...

  3. 1144. The Missing Number (20)

    Given N integers, you are supposed to find the smallest positive integer that is NOT in the given li ...

  4. git 使用远程分支覆盖本地分支(重置本地分支)

    1 丢弃本地变更 重置为远端分支内容 git reset --hard origin/branchName 如 git reset --hard origin/F_AssetItem

  5. Java集合(容器)学习

    1.集合和数组有什么区别,为什么使用集合而不用数组? 相同点:集合和数组都可以存储多个对象,对外作为一个整体存在. 数组的缺点: 长度必须在初始化时指定,且固定不变: 数组采用连续存储空间,删除和添加 ...

  6. File类常用方法和枚举

    新建一个file对象: File f = new File("F:\\01.JAVA基础300集\\05_常用类\\122.File类的使用.mp4"); (文件路径也可以用&qu ...

  7. 【leetcode】870. Advantage Shuffle

    题目如下: 解题思路:几千年前,一个古人曾经解过这个题目,他的名字叫做田忌,后人称他的解题思想叫做“田忌赛马”.言归正传,本题就是一个田忌赛马的问题,先将A与B进行排序,然后判断A[0]与B[0]的大 ...

  8. ES6基本用法

    es6是JS(JavaScript)的下一个版本. 新增了let命令,用来声明变量.变量在第一个花括号内有用,先声明后引用.不允许重复声明.存在暂时性死区. const声明一个只读的常量.一旦声明,常 ...

  9. 一道装呀(状压)DP

    generator 题目描述: 自己的数学太差了,居然没看出来和这两个是相同的: 啊啊啊: 所以装呀一下就好了: #include<iostream> #include<cstdio ...

  10. Pycharm创建模板头部默认

    PyCharm 打开,点击左上角 “FILE” 进入 “Settings”,进行头文件设置: 如下: 我的模板: #!/usr/bin/env python# -*- coding:utf-8 -*- ...