Head First 设计模式 03-装饰者模式
装饰者模式 动态的将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
书中举例说在 java.io 包中有很多类都是装饰者,如 FileInputStream
、FilterInputStream
等,不过感觉在项目倒是感觉很少用到。
各个装饰者之间的关系有点像俄罗斯套娃,一层层的包裹起来。暴露出来的是最外层的装饰者,访问时虽然表面上只访问了最外层的方法,但实际上从外到内依次调用到最底层的组件(有些类似于递归调用)。
这里以旅游公司的产品为例,定义了 Product 产品抽象基类,另外 Line 为旅游线路,Coupon 为优惠券,ResellerLine 为分销商线路。
其类图如下:
使用方法示例如下:
csharp
// 定义线路产品
Product product = new Line("苏州一日游", 500);
// 优惠 50
product = new Coupon(product, 50);
// 旅行社加价 20% 销售
product = new ResellerLine(product, "佳佳旅行社", 1.2);
设计原则
No.5
类应该对扩展开发,对修改关闭。
示例代码
Product
csharp
public abstract class Product
{
public abstract string Description();
public abstract decimal Price();
}
Line
csharp
public class Line : Product
{
private string _name;
private decimal _price;
public Line(string name, decimal price)
{
_name = name;
_price = price;
}
public override string Description()
{
return $"线路名:{_name}";
}
public override decimal Price()
{
return _price;
}
}
Coupon
csharp
public class Coupon : Product
{
private Product _product;
private decimal _discountAmount;
public Coupon(Product product, decimal discountAmount)
{
_product = product;
_discountAmount = discountAmount;
}
public override string Description()
{
return $"{_product.Description()}(优惠 {_discountAmount} 元)";
}
public override decimal Price()
{
return _product.Price() - _discountAmount;
}
}
ResellerLine
csharp
public class ResellerLine : Product
{
private Product _product;
private string _name;
private double _profitRate;
public ResellerLine(Product product, string name, double profitRate)
{
_product = product;
_name = name;
_profitRate = profitRate;
}
public override string Description()
{
return $"{_product.Description()}{Environment.NewLine}经销商: {_name}";
}
public override decimal Price()
{
return decimal.Multiply(_product.Price(), new decimal(_profitRate));
}
}
Program
csharp
class Program
{
static void Main(string[] args)
{
// 定义线路产品
Product product = new Line("苏州一日游", 500);
// 优惠 50
product = new Coupon(product, 50);
// 旅行社加价 20% 销售
product = new ResellerLine(product, "佳佳旅行社", 1.2);
Console.WriteLine(product.Description());
Console.WriteLine($"售价: {product.Price()} 元");
Console.ReadLine();
}
}