Skip to content

Head First 设计模式 03-装饰者模式

🏷️ 《Head First 设计模式》

装饰者模式 动态的将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

书中举例说在 java.io 包中有很多类都是装饰者,如 FileInputStreamFilterInputStream 等,不过感觉在项目倒是感觉很少用到。

各个装饰者之间的关系有点像俄罗斯套娃,一层层的包裹起来。暴露出来的是最外层的装饰者,访问时虽然表面上只访问了最外层的方法,但实际上从外到内依次调用到最底层的组件(有些类似于递归调用)。

这里以旅游公司的产品为例,定义了 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();
    }
}

运行结果