无废话C#设计模式之十三:Decorator

2016-02-19 13:46 11 1 收藏

有了下面这个无废话C#设计模式之十三:Decorator教程,不懂无废话C#设计模式之十三:Decorator的也能装懂了,赶紧get起来装逼一下吧!

【 tulaoshi.com - 编程语言 】

  本系列文章将向大家介绍一下C#的设计模式,此为第十三篇文章,相信对大家会有所帮助的。废话不多说,继续来看。

  意图

  动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。

  场景

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

  在设计网络游戏的武器系统时,开始并没有考虑到武器的强化和磨损。之后,策划人员说希望给游戏增加强化系统和修理系统,那么我们的武器类型就需要对外提供强化、磨损、修理等方法了。发生这种改动是我们最不愿意看到的,按照设计原则,我们希望功能的扩展尽可能不要修改原来的程序。你可能会想到使用继承来实现,但是策划人员的需求是有的武器能磨损能修理,不能强化,有的武器能强化,但是不会磨损,有的武器既能强化还能磨损和修理。遇到这样的情况,继承的方案可能不适合了,一来继承的层次可能会很多,二来子类的数量可能会很多。

  由此,引入装饰模式来解决这个问题。装饰模式使得我们能灵活赋予类额外的职责,并且使得设计和继承相比更合理。

  示例代码

以下是引用片段:
  using System;
  using System.Collections.Generic;
  using System.Text;
  namespace DecoratorExample
  {
  class Program
  {
  static void Main(string[] args)
  {
  Weapon w = new Rifle();
  w.ShowInfo();
  Enhance enhancedWeapon = new Enhance(w);
  enhancedWeapon.EnhanceAmmo();
  enhancedWeapon.ShowInfo();
  Wear wornWeapon = new Wear(w);
  wornWeapon.WearByRate(0.8);
  wornWeapon.ShowInfo();
  }
  }
  abstract class Weapon
  {
  private double ammo;
  public double Ammo
  {
  get { return ammo; }
  set { ammo = value; }
  }
  private double attack;
  public double Attack
  {
  get { return attack; }
  set { attack = value; }
  }
  private double speed;
  public double Speed
  {
  get { return speed; }
  set { speed = value; }
  }
  private string name;
  public string Name
  {
  get { return name; }
  set { name = value; }
  }
  public abstract void ShowInfo();
  }
  class Rifle : Weapon
  {
  public Rifle()
  {
  this.Ammo = 100;
  this.Attack = 10;
  this.Speed = 5;
  this.Name = "Rifle";
  }
  public override void ShowInfo()
  {
  Console.WriteLine(string.Format("ammot{0}", Ammo));
  Console.WriteLine(string.Format("attackt{0}", Attack));
  Console.WriteLine(string.Format("speedt{0}", Speed));
  Console.WriteLine(string.Format("namet{0}", Name));
  }
  }
  abstract class Decorator : Weapon
  {
  protected Weapon w;
  public Decorator(Weapon w)
  {
  this.w = w;
  }
  public override void ShowInfo()
  {
  w.ShowInfo();
  }
  }
  class Enhance : Decorator
  {
  public Enhance(Weapon w) : base(w) { }
  public void EnhanceAmmo()
  {
  w.Ammo += 20;
  Console.WriteLine("Enhanced");
  }
  }
  class Wear : Decorator
  {
  public Wear(Weapon w) : base(w) { }
  public void WearByRate(double rate)
  {
  w.Speed = w.Speed * rate;
  w.Attack = w.Attack * rate;
  Console.WriteLine("Worn");
  }
  }
  }

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

  代码执行结果如下图:

  

  代码说明

  Weapon是抽象构件角色。

  Rifle是具体构件角色,实现抽象构件的接口。

  Decorator是装饰角色。装饰角色有两个特点,一是继承了抽象构件的接口,二是有一个构件角色的实例。

  Enhance和Wear是具体装饰角色,它们负责给构件附加责任。

  客户端在使用装饰角色的时候并没有针对抽象构件进行编程,因为我们确实需要使用具体装饰角色提供的额外方法,这种类型的装饰叫做半透明装饰。

  何时采用

  从代码角度来说,如果你觉得由于功能的交叉扩展不会导致非常多的子类或者非常多的继承层次的话可以考虑装饰模式。

  从应用角度来说,如果你希望动态给类赋予或撤销一些职责,并且可以任意排列组合这些职责的话可以使用装饰模式。

  实现要点

  让装饰角色还继承抽象构件角色也是装饰模式最大的特点,目的就是给抽象构件增加职责,对外表现为装饰后的构件。

  让装饰角色拥有构件角色实例的目的就是让构件能被多个装饰对象来装饰。

  在具体应用中可以灵活一点,不一定要有抽象构件和装饰角色。但是,装饰对象继承装饰对象并且拥有它实例的两大特点需要体现。

  透明装饰一般通过在基类方法前后进行扩充实现,半透明装饰一般通过新的接口实现。

  注意事项

  装饰模式和桥接模式的区别是,前者是针对功能的扩展,本质上还是一样东西,而后者针对多维护变化。装饰模式的思想在于扩展接口而桥接模式的思想是分离接口。

  装饰类可能会比较琐碎,并且不利于复用,装饰模式在增加了灵活性的同时也降低了封装度,在实际应用中可以和其它模式配合。

上一篇:无废话C#设计模式之十二:Bridge

  本系列文章将向大家介绍一下C#的设计模式,此为第十三篇文章,相信对大家会有所帮助的。废话不多说,继续来看。

  意图

  动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。

  场景

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

  在设计网络游戏的武器系统时,开始并没有考虑到武器的强化和磨损。之后,策划人员说希望给游戏增加强化系统和修理系统,那么我们的武器类型就需要对外提供强化、磨损、修理等方法了。发生这种改动是我们最不愿意看到的,按照设计原则,我们希望功能的扩展尽可能不要修改原来的程序。你可能会想到使用继承来实现,但是策划人员的需求是有的武器能磨损能修理,不能强化,有的武器能强化,但是不会磨损,有的武器既能强化还能磨损和修理。遇到这样的情况,继承的方案可能不适合了,一来继承的层次可能会很多,二来子类的数量可能会很多。

  由此,引入装饰模式来解决这个问题。装饰模式使得我们能灵活赋予类额外的职责,并且使得设计和继承相比更合理。

  示例代码

以下是引用片段:
  using System;
  using System.Collections.Generic;
  using System.Text;
  namespace DecoratorExample
  {
  class Program
  {
  static void Main(string[] args)
  {
  Weapon w = new Rifle();
  w.ShowInfo();
  Enhance enhancedWeapon = new Enhance(w);
  enhancedWeapon.EnhanceAmmo();
  enhancedWeapon.ShowInfo();
  Wear wornWeapon = new Wear(w);
  wornWeapon.WearByRate(0.8);
  wornWeapon.ShowInfo();
  }
  }
  abstract class Weapon
  {
  private double ammo;
  public double Ammo
  {
  get { return ammo; }
  set { ammo = value; }
  }
  private double attack;
  public double Attack
  {
  get { return attack; }
  set { attack = value; }
  }
  private double speed;
  public double Speed
  {
  get { return speed; }
  set { speed = value; }
  }
  private string name;
  public string Name
  {
  get { return name; }
  set { name = value; }
  }
  public abstract void ShowInfo();
  }
  class Rifle : Weapon
  {
  public Rifle()
  {
  this.Ammo = 100;
  this.Attack = 10;
  this.Speed = 5;
  this.Name = "Rifle";
  }
  public override void ShowInfo()
  {
  Console.WriteLine(string.Format("ammot{0}", Ammo));
  Console.WriteLine(string.Format("attackt{0}", Attack));
  Console.WriteLine(string.Format("speedt{0}", Speed));
  Console.WriteLine(string.Format("namet{0}", Name));
  }
  }
  abstract class Decorator : Weapon
  {
  protected Weapon w;
  public Decorator(Weapon w)
  {
  this.w = w;
  }
  public override void ShowInfo()
  {
  w.ShowInfo();
  }
  }
  class Enhance : Decorator
  {
  public Enhance(Weapon w) : base(w) { }
  public void EnhanceAmmo()
  {
  w.Ammo += 20;
  Console.WriteLine("Enhanced");
  }
  }
  class Wear : Decorator
  {
  public Wear(Weapon w) : base(w) { }
  public void WearByRate(double rate)
  {
  w.Speed = w.Speed * rate;
  w.Attack = w.Attack * rate;
  Console.WriteLine("Worn");
  }
  }
  }

来源:http://www.tulaoshi.com/n/20160219/1605171.html

延伸阅读
C#中程序结构的关键概念为程序、命名空间、类型、成员和程序集。C#程序包括一个或多个源文件。程序中声明类型,类型包含成员并能够被组织到命名空间中。类和接口是类型的例子。字段、方法、属性和事件则是成员的例子。当C#程序被编译时,它们被物理地打包到程序集中。程序集的文件扩展名一般为.exe或者.dll,这取决于它们是实现为应用程序...
本文目的:根据近期开发的C#软件,对于软件的启动设计谈谈我的心得。 如下代码是我设计的启动软件的类,应用程序入口也是在这个普通类里面。 using System; using System.Threading; using System.Windows.Forms; namespace MainClass { public class MainApp { private static Mutex myMutex; private static bool requestInitialOwnersh...
面向对象思想有三个核心要素:封装、继承与多态。如能正确理解这三要素,那么基本上可以算是在编程中建立了面向对象思想。在第二节中我曾介绍,在C#中,所有数据类型的实例都是对象,不过最能体现对象特质的类型,还是类,同时它也是C#中最重要、最频繁使用的类型。接下来,我将通过介绍C#的类,来充分理解对象封装的概念。 所谓对象...
C#是纯粹的面向对象编程语言,它真正体现了一切皆为对象的精神。在C#中,即使是最基本的数据类型,如int,double,bool类型,都属于System.Object类型。此外,使用C#编程,不会存在与游离于对象之外的属于过程的东西。因此,学习C#,就必须具有面向对象思想,不明白所谓的面向对象思想,就不可能掌握C#的精髓,而对于C#的理解,就只能仅限...
本文讲解的是你在建立包含内存以外资源的类型,特别是处置非内存资源的时候,如何编写自己的资源管理代码。 我们已经知道了处置那些占用非受控(unmanaged)资源的对象的重要性,现在应该编写资源管理代码来处置那些包含非内存资源的类型了。整个.NET框架组件都使用一个标准的模式来处理非内存资源。使用你建立的类型的用户也希望你遵...

经验教程

396

收藏

65
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部