装饰者模式的主要功能是通过对象组合的方式来拓展对象的具体功能,通过装饰者模式,可以让对象脱离继承的束缚。
装饰者模式的框架类图如下:
由图中可以看出:装饰者(Decorator)和被装饰者(ConcreteComponent)都继承自同一个接口/抽象类。这也是装饰者模式的特点,通过这种方式可以更方便后面装饰者和被装饰者之间的组合。
其实所谓的组合,更形象点说是用装饰者把被装饰者给包装起来(把被装饰者的对象引用加到装饰者的对象中去)。下面我们来看一下具体的实现代码。
1:首先我们要创建Component抽象类/接口(本实例中用的是接口)
interface Beverage
{
double Kosten { get; set; }
String Description { get; set; }
String GetDescription();
double Cost();
}
设计模式中有一个重要原则就是:把要变化的行为和属性分离出来。这里我们把一些装饰者和被装饰者所应该共有的方法和属性加入公共的接口中。
2:然后我们来写Decorator的抽象类
abstract class Decorator:Beverage
{
protected Beverage beverage;
public double Kosten { get; set; }
public string Description { get; set; }
public abstract string GetDescription();
public virtual double Cost()
{
return beverage.Cost() + Kosten;
}
}
此类中把 Cost实现了,并且设为virtual是为了让继承它的所有子类可以直接调用Cost()方法,如果需要修改调料的价格,则只需要重写此方法即可。
3:开始编写修饰者和被修饰者的实体类:
一个具体的意大利浓咖啡类(被修饰者):
class Expresso:Beverage
{
public double Kosten { get; set; }
public string Description { get; set; }
public Expresso(double kosten, String description)
{
this.Kosten = kosten;
this.Description = description;
}
public string GetDescription()
{
return this.Description+" with ";
}
public double Cost()
{
return this.Kosten;
}
}
一个具体的牛奶类(修饰者)
class Milk:Decorator
{
public Milk(double kosten,String description,Beverage beverage)
{
this.Description = description;
this.Kosten = kosten;
this.beverage = beverage;
}
public override string GetDescription()
{
return this.beverage.GetDescription() +" "+ this.Description;
}
public override double Cost()
{
return this.beverage.Cost() + this.Kosten*0.8;
}
}
这里我们重写了牛奶类的Cost方法(给价格打了个8折)
4:调用
class Program
{
static void Main(string[] args)
{
Expresso ex1 = new Expresso(2.0, "expresso");
Milk m1=new Milk(0.5,"little Milk",ex1);
Milk m2=new Milk(0.8,"big Milk",m1);
Console.WriteLine(m2.GetDescription()+" $"+m2.Cost());
Console.ReadKey();
}
}
总结:个人觉得装饰者模式有一个很大的缺点,就是经过“装饰”后的对象类型已经不是原来的类的对象了,虽然它们还是继承自原来那个接口/抽象类,但是想要获得被装饰的类的具体类信息,已经不太可能了。
JS端使用装饰者模式:
JS代码不具有继承,所以在使用装饰者模式的时候有点摸不着头脑,笔者强行创建了两个JS类,然后通过组合的方式勉强实现了此设计模式:
function Decorator(kosten,description,obj){
this.beverage=obj;
this.description=description;
this.kosten=kosten;
this.GetDescription=function(){
return this.beverage.GetDescription()+" "+this.description;
}
this.Cost=function(){
return this.beverage.Cost()+this.kosten;
}
}
function Drinks(kosten,description){
this.description=description;
this.kosten=kosten;
this.GetDescription=function(){
return this.description;
}
this.Cost=function(){
return this.kosten;
}
}
var expresso=new Drinks(3,"this is a Expresso");
var milk=new Decorator(0.8,"milk",expresso);
alert(milk.GetDescription()+" $"+milk.Cost());
PS:第一次写博文,如有错漏,欢迎指正