经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » 设计模式 » 查看文章
C#设计模式-装饰器模式(Decorator Pattern)
来源:cnblogs  作者:Tynam.Yang  时间:2020/12/8 9:08:24  对本文有异议

引言

当我们完成一个软件产品开发后就需要对其进行各种测试,适配快速迭代下质量的保障。当有一个完善的产品的对象后,如果我们想要给他添加一个测试功能,那么我们可以用一个新的类去装饰它来实现对原有对象职责的扩展。新的类称为“装饰者”,原有的对象称为“被装饰者”。这种模式被称为装饰器模式。

概念

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
我们通过下面的实例来演示装饰器模式的用法。其中,我们将把一个形状装饰上不同的颜色,同时又不改变形状类。

结构图

装饰器模式中的角色:

  • 抽象构件(Component)角色:声明封装器和被封装对象的公用接口。即给出一个抽象接口,已规范准备接收附加责任的对象。
  • 具体构件(ConcreteComponent)角色:类是被封装对象所属的类。 它定义了基础行为, 但装饰类可以改变这些行为。
  • 装饰(Decorator)角色:拥有一个指向被封装对象的引用成员变量。 该变量的类型应当被声明为通用部件接口, 这样它就可以引用具体的部件和装饰。 装饰基类会将所有操作委派给被封装的对象。
  • 具体装饰(ConcreteDecorator)角色:定义了可动态添加到部件的额外行为。 具体装饰类会重写装饰基类的方法, 并在调用父类方法之前或之后进行额外的行为。负责给构件对象“贴上”附加的责任。

实现

实现一个开发完成后的产品,对其进行手工功能测试、自动化测试、压力测试。将产品作为被装饰者,也就是构件。各种测试作为装饰者,计算附加不同的测试花费的总时间。

实现思路:

  • 定义一个产品抽象类。
  • 实现具体的产品,具体的产品继承产品抽象类。
  • 定义一个测试类型的抽象装饰类,继承产品抽象类。
  • 实现不同类型的测试,继承测试类型的抽象装饰类。
  • 使用时实例化一个产品,然后对产品进行附件不同的测试类型。
  1. using System;
  2. namespace Decorator
  3. {
  4. class Program
  5. {
  6. static void Main(string[] args)
  7. {
  8. Product a = new ProductA();
  9. Console.WriteLine($"未执行{a.Test}测试时总共花费时间{a.TotalTime}");
  10. a = new ManualTest(a);
  11. Console.WriteLine($"执行{a.Test}总共花费时间{a.TotalTime}");
  12. Console.WriteLine("=====================================");
  13. Product b = new ProductB();
  14. b = new ManualTest(b);
  15. b = new StressTest(b);
  16. b = new AutoTest(b);
  17. Console.WriteLine($"执行{b.Test}总共花费时间{b.TotalTime}");
  18. Console.Read();
  19. }
  20. }
  21. /// <summary>
  22. /// 一个项目产品,抽象构件
  23. /// </summary>
  24. public abstract class Product
  25. {
  26. public string Name { get; set; }
  27. public double SpendTime { get; set; }
  28. public abstract string Test { get; }
  29. public abstract double TotalTime { get; }
  30. }
  31. /// <summary>
  32. /// 具体的项目产品A,具体构件
  33. /// </summary>
  34. public class ProductA : Product
  35. {
  36. public ProductA()
  37. {
  38. Name = "ProductA";
  39. SpendTime = 0;
  40. }
  41. public override string Test => this.Name;
  42. public override double TotalTime => this.SpendTime;
  43. }
  44. /// <summary>
  45. /// 具体的项目产品B,具体构件
  46. /// </summary>
  47. public class ProductB : Product
  48. {
  49. public ProductB()
  50. {
  51. Name = "ProductB";
  52. SpendTime = 0;
  53. }
  54. public override string Test => this.Name;
  55. public override double TotalTime => this.SpendTime;
  56. }
  57. /// <summary>
  58. /// 测试类型,抽象装饰
  59. /// </summary>
  60. public abstract class TestType : Product
  61. {
  62. Product _product = null;
  63. public TestType(Product product)
  64. {
  65. _product = product;
  66. }
  67. public override string Test
  68. {
  69. get
  70. {
  71. return _product.Test + "+" + this.Name;
  72. }
  73. }
  74. public override double TotalTime
  75. {
  76. get
  77. {
  78. return _product.TotalTime + this.SpendTime;
  79. }
  80. }
  81. }
  82. /// <summary>
  83. /// 手工测试类型,具体装饰
  84. /// </summary>
  85. public class ManualTest : TestType
  86. {
  87. public ManualTest(Product product) : base(product)
  88. {
  89. Name = "手工测试";
  90. SpendTime = 200;
  91. }
  92. }
  93. /// <summary>
  94. /// 自动化测试类型,具体装饰
  95. /// </summary>
  96. public class AutoTest : TestType
  97. {
  98. public AutoTest(Product product) : base(product)
  99. {
  100. Name = "自动化测试";
  101. SpendTime = 100;
  102. }
  103. }
  104. /// <summary>
  105. /// 压力测试类型,具体装饰
  106. /// </summary>
  107. public class StressTest : TestType
  108. {
  109. public StressTest(Product product) : base(product)
  110. {
  111. Name = "压力测试";
  112. SpendTime = 200;
  113. }
  114. }
  115. }

运行后结果:

  1. 未执行ProductA测试时总共花费时间0
  2. 执行ProductA+手工测试总共花费时间200
  3. =====================================
  4. 执行ProductB+手工测试+压力测试+自动化测试总共花费时间500

应用场景

  • 在无需修改代码的情况下即可使用对象, 且希望在运行时为对象新增额外的行为时可以使用装饰模式。因为装饰能将业务逻辑组织为层次结构,可为各层创建一个装饰, 在运行时将各种不同逻辑组合成对象。 由于这些对象都遵循通用接口, 客户端代码能以相同的方式使用这些对象。
  • 如果用继承来扩展对象行为的方案难以实现或者根本不可行,可以使用装饰模式。

优缺点

优点

  • 无需创建新子类即可扩展对象的行为。
  • 可以在运行时添加或删除对象的功能。
  • 可以用多个装饰封装对象来组合几种行为。
  • 装饰类和被装饰类可以独立发展,不会相互耦合。
  • 单一职责原则。 可以将实现了许多不同行为的一个大类拆分为多个较小的类。

缺点

  • 在封装器栈中删除特定封装器比较困难。
  • 实现行为不受装饰栈顺序影响的装饰比较困难。
  • 各层的初始化配置代码看上去可能会很糟糕。

 

原文链接:http://www.cnblogs.com/tynam/p/14037615.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号