引子

在面向对象语言中,我们常常会听到这样一句话:组合优于继承.那么该如何去理解这句话呢?

下面我将以游戏装备为模型用简单的代码去展示它

先创建一个装备的抽象类,然后创建刀枪2个具体的业务子类

  public abstract class AbstractEquipment
{
public int Id { get; set; } public string Name { get; set; } public abstract void Attack();
} public class Gun : AbstractEquipment
{
public override void Attack()
{
Console.WriteLine("用枪攻击");
}
} class Sword : AbstractEquipment
{
public override void Attack()
{
Console.WriteLine("用剑攻击");
}
}

面对这样的场景,我们常常会提出这样的疑问:如何面对业务扩展?例如,此时需要添加一个新的功能:在装备攻击后,会提醒善恶值增加

在不修改业务子类的前提下,我们通过继承和组合两种不同的方式来解决,如下:

   //继承
public class GunInherit:Gun
{
public override void Attack()
{
base.Attack();
Console.WriteLine("善恶值增加");
}
} //组合
public class EquipmentCombination
{
private AbstractEquipment _equipment = null;
public EquipmentCombination(AbstractEquipment equipment)
{
_equipment = equipment;
} public void Attack()
{
_equipment.Attack();
Console.WriteLine("善恶值增加");
}
}

观察上述代码可以得到以下结论

继承:虽然代码少,但是强侵入,强关联,只能为特定类服务

组合:虽然加了一个全新类,增加了代码量,但是非常灵活

在这么少量的代码下,已经能够看到继承的劣势,那么随着功能需求的增加,仅仅靠继承来扩展业务,那将会带来巨大的弊端.

装饰器模式

装饰器模式是通过上述组合加继承的方式,动态的为业务类添加功能的一种设计模式

在这种设计模式之下,只需要添加一个新的装饰器,即可为业务类添加一个新的功能

首先对装饰器进行一次抽象,相比于单单组合的方式,这样可以减少代码复杂程度

      public class BaseEquipmentDecorator : AbstractEquipment
{
private AbstractEquipment _equipment = null;
public BaseEquipmentDecorator(AbstractEquipment equipment)
{
_equipment = equipment;
}
public override void Attack()
{
_equipment.Attack();
}
}

一旦业务类需要添加新功能,只需要继承上面的装饰器基类,加上新功能即可,例如:为装备添加强化的功能

     public class EquipmentStrengthenDecorator:BaseEquipmentDecorator
{
//调用直接父类的指定构造函数
public EquipmentStrengthenDecorator(AbstractEquipment equipment)
:base(equipment)
{ }
public override void Attack()
{
base.Attack();
Strengthen();
}
public void Strengthen()
{
Console.WriteLine("武器被强化");
}
}

调用:

    class Program
{
static void Main(string[] args)
{
AbstractEquipment gun = new Gun();
gun = new EquipmentStrengthenDecorator(gun);
gun.Attack();
Console.ReadKey();
}
}

打印:

用枪攻击

武器被强化

这样,强化的功能就添加到了装备之中了

通过继承加组合的装饰器模式,我们可以灵活的动态添加对象的功能职责

装饰器模式类图

装饰器模式4种角色:

抽象业务角色(AbstractEquipment):具体业务类的抽象;

具体业务角色(Gun,Sword):具体业务类,被装饰的直接对象;

装饰器基类角色(BaseEquipmentDecorator):具体装饰器的基类;

具体装饰器角色(EquipmentStrengthenDecorator):提供具体的功能去装饰具体业务角色;

装饰器模式优缺点及使用场景

优点:灵活,扩展性好,能够在不影响业务类的前提下,动态的为其添加本身不存在的功能

缺点:增加了程序的复杂程度

使用场景:为具体的业务对象附加功能职责,例如上述的游戏装备,以及培训班的各层vip,商场的多重优惠等等

出自:博客园-半路独行

原文地址:https://www.cnblogs.com/banluduxing/p/9152453.html

本文出自于http://www.cnblogs.com/banluduxing 转载请注明出处。

代码地址:https://github.com/weiweu/My-space/tree/master/Design/DecoratorPattern

c#设计模式之装饰器模式(Decorator Pattern)的更多相关文章

  1. python 设计模式之装饰器模式 Decorator Pattern

    #写在前面 已经有一个礼拜多没写博客了,因为沉醉在了<妙味>这部小说里,里面讲的是一个厨师苏秒的故事.现实中大部分人不会有她的天分.我喜欢她的性格:总是想着去解决问题,好像从来没有怨天尤人 ...

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

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

  3. 【UE4 设计模式】装饰器模式 Decorator Pattern

    概述 描述 动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活.是一种对象结构型模式. 套路 抽象构件(Component) 具体构 ...

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

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

  5. 设计模式(三)——装饰器模式(Decorator Pattern)

    发现太过于刻意按照计划来写博客,有点不实际,刚好最近在一个网课上复习AOP的知识,讲到了装饰器模式和代理模式,顺便复习总结一下. 首先了解一下装饰器模式,从名字里面可以看出来,装饰器模式就类似于房子装 ...

  6. 用最简单的例子理解装饰器模式(Decorator Pattern)

    假设有一个公司要做产品套餐,即把不同的产品组合在一起,不同的组合对应不同的价格.最终呈现出来的效果是:把产品组合的所有元素呈现出来,并显示该组合的价格. 每个产品都有名称和价格,首先设计一个关于产品的 ...

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

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

  8. php装饰器模式(decorator pattern)

    十一点了. <?php /* The decorator pattern allows behavior to be added to an individual object instance ...

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

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

随机推荐

  1. 分享一个jquery插件,弥补一下hover事件的小小不足

    hover事件有一个缺点:当你的鼠标无意划过一个dom元素(瞬间划过,这个时候用户可能不想触发hover事件),会触发hover事件 应该设置一个时差来控制hover事件的触发 比如jd左边的菜单 你 ...

  2. C# 二元一次方程参数求解

    本文记录了关于求直线斜率及纵截距值的简单方法,只是简单的记录下求解思路,最终还需根据具体项目进行优化. 设直线方程式为:y=kx+b 编程思想: 1.代入y1与x1的值,得到:y1=kx1+b 2.代 ...

  3. sonar 的使用

    1.依赖: <dependency> <groupId>org.codehaus.mojo</groupId> <artifactId>sonar-ma ...

  4. firemonkey Grid自定义

    http://stackoverflow.com/questions/28893564/memory-leak-on-tstringgrids-ondrawcolumncell-event http: ...

  5. Memo synEditor 当前行号

    Memo 当前行号,坐标,位置 可以使用Memo的属性CaretPos.X来取行鼠标所在行的行数与鼠标所在行的第几位 Memo.CaretPos.X 光标或鼠标所在行的列号(第几位),从0开始计数Me ...

  6. [ML]熵、KL散度、信息增益、互信息-学习笔记

    [ML]熵.KL散度.信息增益.互信息-学习笔记 https://segmentfault.com/a/1190000000641079

  7. Android开发之获取系统所有进程信息。

    最近在做一个app,有一个进程管理模块用于管理系统中正在运行的进程,并且可以关闭进程进行加速手机的功能,基本把它实现了出来.界面的效果都是自己写的,虽然有BUG,但是基本上能满足需求,后期我会改进BU ...

  8. C# \/date(1498820611133+0800)\/ 转DateTime

    开发中经常遇到日期转换问题,特别是做接口的时候,现在整理了下时间戳转为C#格式时间的方法: /// <summary> /// 时间戳转为C#格式时间 /// </summary&g ...

  9. MVC DbContext

    指定数据连接,指定表名,移除表名复数化(表名后面不加s),设置字段约束,主外键关系. using MvcApplication1.Models; using System; using System. ...

  10. Ubuntu下U盘只读文件系统,图标上锁,提示无法修改

    资料来源于网络,自己总结 问题 Ubuntu下有时候插入U盘,发现不能修改其中的内容.例如不能新建文件和文件夹,不能向U盘中复制文件等,系统提示:只读文件系统. 原因大概是U盘的文件系统信息出错(保存 ...