这个线程,Decorator模式实现,有一个使用抽象类的装饰器的实现.我不喜欢它的简单事实,即CondimentDecorator不是那里给出的实施中的饮料.我会使用接口代替.对于is-a关系而言,抽象类不是更好吗?对于has-a关系,接口更好吗?
public interface IBeverage
{
// get a description of the beverage
String Description { get; }
// calculate cost of the beverage
double Cost { get; }
}
// HouseBlend coffee implements IBeverage
public class HouseBlend : IBeverage
{
private string description;
public String Description
{
get { return description; }
}
private double cost;
public double Cost
{
get { return cost; }
}
// Constructor
public HouseBlend() { description = "House Blend"; cost = 0.89; }
}
// DarkRoast coffee implements IBeverage
public class DarkRoast : IBeverage
{
private string description;
public String Description
{
get { return description; }
}
private double cost;
public double Cost
{
get { return cost; }
}
// Constructor
public DarkRoast() { description = "Dark Roast"; cost = 1.10; }
}
// Mocha is a Decorator
public class Mocha
{
// Mocha has-a Beverage
private IBeverage m_beverage;
private string description;
public String Description
{
get { return description; }
}
private public double Cost
{
get { return cost; }
}
// Constructor binds the object passed to member var
public Mocha(IBeverage beverage)
{
m_beverage = beverage; // not necessary for the purpose of this example
description = m_beverage.Description + ", Mocha";
cost = 0.20 + m_beverage.Cost;
}
}
Use like this:
Mocha mhb = new Mocha(new HouseBlend()); // house blend with mocha flavor
Run Code Online (Sandbox Code Playgroud)
基类和接口都经常用于建模 is-a 关系。即使是一个简单到IDisposable可以理解为“是一个具有手动控制生命周期的对象”、“一次性”的接口。更明显的区别在于是否允许基本实现或数据字段;以及他们组合多个层次结构的能力。
现在,当您实现任何模式时,您通常有足够的信息来查看是否需要数据字段。然而,随着软件的发展,您几乎永远无法排除未来需要在其他模式中涉及相同的类。从这个角度来看,接口相对于抽象类的普遍偏好为您提供了更多的长期灵活性 - 无论何时您有选择。
根据装饰器的本质,您可以选择。这些组件通常没有预定义的嵌套顺序。如果这样做,您将直接使用继承,而不是组件。所以你应该更喜欢用接口来组成装饰器。
综上所述,您最初的论点也是有效的。如果你愿意,装饰器组件(功能)可以理解为 is-a 关系;但这并不是最自然的看待它们的方式。