设计模式之装饰者模式
定义
动态的将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
设计原则
类应该对扩展开发,对修改关闭。
第一次设计
现在我们有一家饮料店,下面是它最开始的设计。
Beverage是一个抽象类,店内所有提供的饮料都要继承自此类。并且每个子类都要实现cost()来返回饮料的价格。
很明显,这样使得维护变成了一个噩梦。
第二次设计
我们从它的基类入手,给每一个调料代表一个bool值,cost()不再是一个抽象方法,我们在基类中提供它的实现,然后根据调料的布尔值计算它的价格。
在子类中,覆盖过的cost()会扩展超类的功能,把指定的饮料类型的价钱也加进来(同时加上父类cost()的总价)。
下面让我们看看这样设计的问题:
- 调料价格改变需要更改现有代码
- 出现新的调料,需要加上新的方法和修改cost()方法。
- 如果顾客需要双份调料怎么办
开放-关闭原则
设计原则:类应该对扩展开放,对修改关闭。
我们的目标是允许类容易扩展,在不修改现有代码的情况下,就可搭配新的行为。这样设计具有弹性可以应对改变,可以接受新的功能来应对改变的需求。
第三次设计
下面开始我们的设计:
我们以饮料为主体,然后在运行时以调料来装饰饮料。
现在我们需要一杯摩卡和奶泡深焙咖啡。
1.拿一个深焙咖啡(DarkRoast)对象
以DarkRoast对象开始。DarkRoast继承自Beverage,并且有一个计算饮料价钱的cost()方法。
2.以摩卡(Mocha)对象装饰它
建立一个Mocha对象,并用它将DarkRoast对象包起来。
Mocha对象是一个装饰者,它的类型反映了它所装饰的对象(这里就是Bevarage)。
反映:就是两个类型一致。
Mocha也有一个cost()方法。通过多态,也可以把Mocha所包裹的任何Bevarage当成Bevarage。
3.以奶泡(Whip)对象装饰它
建立一个Whip装饰者,并用它将Mocha对象包起来。DarkRoast继承自Bevarage,且有一个cost()方法,用来计算饮料价格。
Whip是一个装饰者,它也反映了DarkRoast类型,并包括cost()方法。
被Mocha和Whip包起来的DarkRoast对象仍然是一个Bevarage,仍然可以具有DarkRoast的一切行为,包括调用它的cost()方法。
4.调用cost()方法,并依赖委托将调料的价钱加上去
现在到了算钱的时候。通过调用最外围装饰者(Whip)的cost()就可以了。Whip对象的cost()会先委托它的装饰的对象(Mocha)计算出价钱,然后再加上奶泡的价钱。
定义装饰者模式
动态的将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
实现
类图
Beverage
public abstract class Beverage//抽象类 { public string description = "Unknow Beverage"; public virtual string getDescription()//已经实现 { return description; } public abstract double cost();//必须在子类中实现 }
调料抽象类
public abstract class ComdimentDecorator : Beverage////抽象装饰者 { public abstract string getDescription();//所有的调料都必须重新实现此方法 }
饮料代码
public class Espresso : Beverage//让Espresso扩展自Beverage,因为Espresso是一种饮料 { public override string getDescription()//设置饮料的描述 { return "Espresso"; } public override double cost()//计算Espresso价格,现在不管调料价格 { return 1.99; } }
public class HouseBlend : Beverage//具体组件 { public override string getDescription() { return "House Blend"; } public override double cost() { return 0.89; } }
调料代码
public class Mocha : ComdimentDecorator//装饰者 { private Beverage beverage;//用一个实例变量记录饮料,也就是被装饰者 public Mocha(Beverage beverage)//把饮料当作构造器的参数,在由构造器将此饮料记录在实例变量中 { this.beverage = beverage; } public override double cost() { return 0.2 + beverage.cost(); } public override string getDescription() { return beverage.getDescription() + ",Moche"; } }
测试
static void Main(string[] args) { Beverage beverage = new Espresso(); beverage = new Mocha(beverage); Console.WriteLine(beverage.getDescription() + "$" + beverage.cost()); Beverage beverage2 = new Espresso();//制造一个Espresso对象 beverage2 = new Mocha(beverage2);//用Mocha装饰它 beverage2 = new Mocha(beverage2);//用第二杯Mocha装饰它 beverage2 = new Whip(beverage2);//用Whip装饰它 Console.WriteLine(beverage2.getDescription() + "$" + beverage2.cost()); Beverage beverage3 = new HouseBlend(); beverage3 = new Soy(beverage3); beverage3 = new Mocha(beverage3); beverage3 = new Whip(beverage3); beverage3.getDescription(); Console.WriteLine(beverage3.getDescription() + "$" + beverage3.cost()); Console.ReadLine(); }
如本文对您有帮助请移步右下角,推荐本文,谢谢大家的点赞,因为您的支持是我最大动力