装饰者模式
问题场景
如果要计算一杯咖啡的价格,只需要调用其获取价格的方法就可以了,但是如果需要加一些材料,比如牛奶、巧克力、糖等等,这些材料也必须返回它们价格以便于用于汇总计算,但是材料有很多,我们并不能事先预测买家需要哪些材料,所以似乎只能在咖啡类中做出判定去确认买家需要的材料后才能计算出结果,但这并不是一个好的解决思路,由于材料可能有上100种,我们不可能写100次判断去确认加的是哪些材料,况且今后有新进的材料,还得继续多处修改代码。解决方式是使用抽象类和包装器,抽象类提供可重写的获取价格的方法,由饮料子类去实现自身的价格,而材料也可以从同一个抽象类派生,这样,饮料类只需要返回自身的价格,而材料类则依赖于抽象类的实现(饮料类),调用抽象类的获取价格的方法并加上材料自身的价格就可以在外部调用材料时计算出总价格。
总结模式
在不改动类型结构的情况下,只利用现有代码为类型附加其它的功能。装饰者也叫包装器,包装器需要依赖一个抽象类的具体实现类,以便调用依赖对象的方法获取结果。
代码示例
namespace AppCUI
{
//超类
public abstract class Drink
{
public abstract double GetPrice( );
}
//具体的饮料
public class Coffe : Drink
{
//返回自身的价格
public override double GetPrice( )
{
return 12.5;
}
}
//具体的材料也从饮料派生,以便重写价格
public class Milk : Drink
{
//饮料的价格需要附加我的价格,所以我需要得到饮料,以便计算总价格
private Drink drink;
//饮料抽象的具体类通过构造函数注入给我
public Milk( Drink drink )
{
this.drink = drink;
}
//计算总价格
public override double GetPrice( )
{
return 1.2 + drink.GetPrice( );
}
}
public class Chocolate : Drink
{
private Drink drink;
public Chocolate( Drink drink )
{
this.drink = drink;
}
public override double GetPrice( )
{
return 1.5 + drink.GetPrice( );
}
}
public class Programe
{
static void Main( string[] args )
{
Drink drink = new Coffe( ); //我要一杯咖啡
drink = new Milk( drink ); //咖啡需要加牛奶
drink = new Chocolate( drink ); //牛奶咖啡需要加糖
Console.WriteLine( drink.GetPrice( ) ); //巧克力内部维护了牛奶咖啡的价格,牛奶维护了咖啡的价格,返回路径:咖啡价格=>牛奶+咖啡价格=>巧克力+牛奶咖啡价格
}
}
}
{
//超类
public abstract class Drink
{
public abstract double GetPrice( );
}
//具体的饮料
public class Coffe : Drink
{
//返回自身的价格
public override double GetPrice( )
{
return 12.5;
}
}
//具体的材料也从饮料派生,以便重写价格
public class Milk : Drink
{
//饮料的价格需要附加我的价格,所以我需要得到饮料,以便计算总价格
private Drink drink;
//饮料抽象的具体类通过构造函数注入给我
public Milk( Drink drink )
{
this.drink = drink;
}
//计算总价格
public override double GetPrice( )
{
return 1.2 + drink.GetPrice( );
}
}
public class Chocolate : Drink
{
private Drink drink;
public Chocolate( Drink drink )
{
this.drink = drink;
}
public override double GetPrice( )
{
return 1.5 + drink.GetPrice( );
}
}
public class Programe
{
static void Main( string[] args )
{
Drink drink = new Coffe( ); //我要一杯咖啡
drink = new Milk( drink ); //咖啡需要加牛奶
drink = new Chocolate( drink ); //牛奶咖啡需要加糖
Console.WriteLine( drink.GetPrice( ) ); //巧克力内部维护了牛奶咖啡的价格,牛奶维护了咖啡的价格,返回路径:咖啡价格=>牛奶+咖啡价格=>巧克力+牛奶咖啡价格
}
}
}