引子

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

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

先创建一个装备的抽象类,然后创建刀枪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. 测试Linux端口的连通性的四种方法

    Linux系统有时候需要测试某个端口的连通性,用户可以参考如下方法来测试.   方法一.telnet法 telnet为用户提供了在本地计算机上完成远程主机工作的能力,因此可以通过telnet来测试端口 ...

  2. 有了 itchat, python 调用微信个人号从未如此简单(新增 py3 支持)

    itchat 是一个开源的微信个人号接口. 近期完成了 py3 与文档的完善,欢迎各位使用与测试. 使用不到三十行的代码,你就可以完成一个能够处理所有信息的微信机器人. 当然,该 api 的使用远不止 ...

  3. 运维工具shell简介

    运维第一工具-shell编程 shell历史 Shell的作用是解释执行用户的命令,用户输入一条命令,Shell就解释执行一条,这种方式称为交互式(Interactive),Shell还有一种执行命令 ...

  4. 好记性不如烂笔头-linux学习笔记4apache相关知识

    apache 启动有2种模式 1是prefork模式,每个进程对应一个线程,如果是比较稳定的平台,那么prefork模式是worker模式 比较好,效率高,但是吃的内存比较大. 2 如果是高负载高并发 ...

  5. VS2010开发MFC ActiveX,摄像头拍照上传Webservice(1)

    最近工作项目,BS中需要用到摄像头拍照,需要存储本地,同时上传到服务器,尝试使用vc++做ActiveX来实现. 完全没有使用过vc,上网搜索各种知识,初步完成.在这里记录下有帮助的资料. 第一步:编 ...

  6. asp.net 初级程序员面试题【待续】

     C# 常见的排序方式 冒泡排序(Bubble sort) 堆排序(Heap sort) 插入排序(Insertion sort) 归并排序(Merge sort) 快速排序(Quick sort) ...

  7. Spring Cloud Bus实现自动更新配置

    一.概述 1. 配置环境 版本:Spring Boot版本2.0.3.RELEASE,Spring Cloud版本Finchley.SR1,RabbitMQ 3.7.7 说明:本文章是在https:/ ...

  8. 更改FP SYSTEM密码

    1 Please create a new account and set a new password 2 backup table ABPPMGR.USER_PROFILE , ABPPMGR . ...

  9. Associate File Type with Qt In Mac Os and Win

    Win Registry Question One day, my boss want me to finish one function which let the users can double ...

  10. DALSA网口线扫相机SDK开发详解例程(C#版)

    首先吐槽一句,官方的demos写的真的不好,坑爹啊.对于小白来说,开发官方demos为我所用太难了.为什么呢?因为它Dalsa的DALSA.SaperaLT.SapClassBasic.dll中,不仅 ...