引子
在面向对象语言中,我们常常会听到这样一句话:组合优于继承.那么该如何去理解这句话呢?
下面我将以游戏装备为模型用简单的代码去展示它
先创建一个装备的抽象类,然后创建刀枪2个具体的业务子类
1 public abstract class AbstractEquipment 2 { 3 public int Id { get; set; } 4 5 public string Name { get; set; } 6 7 public abstract void Attack(); 8 } 9 10 public class Gun : AbstractEquipment 11 { 12 public override void Attack() 13 { 14 Console.WriteLine("用枪攻击"); 15 } 16 } 17 18 class Sword : AbstractEquipment 19 { 20 public override void Attack() 21 { 22 Console.WriteLine("用剑攻击"); 23 } 24 }
面对这样的场景,我们常常会提出这样的疑问:如何面对业务扩展?例如,此时需要添加一个新的功能:在装备攻击后,会提醒善恶值增加
在不修改业务子类的前提下,我们通过继承和组合两种不同的方式来解决,如下:
1 //继承 2 public class GunInherit:Gun 3 { 4 public override void Attack() 5 { 6 base.Attack(); 7 Console.WriteLine("善恶值增加"); 8 } 9 } 10 11 //组合 12 public class EquipmentCombination 13 { 14 private AbstractEquipment _equipment = null; 15 public EquipmentCombination(AbstractEquipment equipment) 16 { 17 _equipment = equipment; 18 } 19 20 public void Attack() 21 { 22 _equipment.Attack(); 23 Console.WriteLine("善恶值增加"); 24 } 25 }
观察上述代码可以得到以下结论
继承:虽然代码少,但是强侵入,强关联,只能为特定类服务
组合:虽然加了一个全新类,增加了代码量,但是非常灵活
在这么少量的代码下,已经能够看到继承的劣势,那么随着功能需求的增加,仅仅靠继承来扩展业务,那将会带来巨大的弊端.
装饰器模式
装饰器模式是通过上述组合加继承的方式,动态的为业务类添加功能的一种设计模式
在这种设计模式之下,只需要添加一个新的装饰器,即可为业务类添加一个新的功能
首先对装饰器进行一次抽象,相比于单单组合的方式,这样可以减少代码复杂程度
1 public class BaseEquipmentDecorator : AbstractEquipment 2 { 3 private AbstractEquipment _equipment = null; 4 public BaseEquipmentDecorator(AbstractEquipment equipment) 5 { 6 _equipment = equipment; 7 } 8 public override void Attack() 9 { 10 _equipment.Attack(); 11 } 12 }
一旦业务类需要添加新功能,只需要继承上面的装饰器基类,加上新功能即可,例如:为装备添加强化的功能
1 public class EquipmentStrengthenDecorator:BaseEquipmentDecorator 2 { 3 //调用直接父类的指定构造函数 4 public EquipmentStrengthenDecorator(AbstractEquipment equipment) 5 :base(equipment) 6 { 7 8 } 9 public override void Attack() 10 { 11 base.Attack(); 12 Strengthen(); 13 } 14 public void Strengthen() 15 { 16 Console.WriteLine("武器被强化"); 17 } 18 }
调用:
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