需要从decorator设计模式中的组件派生decorator



我在学习设计模式教程时遇到了装饰器模式。我知道如何以及何时使用decorator模式,但是,我有点困惑为什么decorator需要从组件派生。

我看到的例子如下:

//Component classes
public abstract class Car
{
public abstract int GetPrice();
//Other properties and methods
}
public class ActualCar : Car
{
public int GetPrice(){return 1000;}
}
//Decorators classes
public class CarDecorator : Car //No idea why this is necessary
{
protected Car car;
public CarDecorator(Car car)
{
this.car = car;
}
public override int GetPrice() => this.car.GetPrice();
}
public class LeatherSeats : CarDecorator
{
public LeatherSeats(Car car) : base(car){}
public override int GetPrice() => this.car.GetPrice() + 200;
}
public class AlloyWheels : CarDecorator
{
public AlloyWheels(Car car) : base(car) {}
public override int GetPrice() => this.car.GetPrice() + 150;
}

现在,当使用组件及其装饰器时,我们将其用作:

Car newCar = new ActualCar();
int price = new AlloyWheels(new LeatherSeats(newCar)).GetPrice();

现在我觉得奇怪的是,CarDecorator是从Car继承而来的,因为无论你怎么看,它都不遵循is-一种类型的关系。所以我又看了几个例子,意识到装饰器模式就是这样设计的。

我不想质疑decorator模式以这种方式设计的原因,只想知道没有从它包装的组件派生decorator图案会有什么缺点。

作为基本装饰器的CarDecorator应该继承Car接口(这里是一个抽象类(,以确保CarDecorator已经实现(应该覆盖(GetPrice方法。

如果CarDecorator不是从Car继承的,那么就不能这样做:

Car newCar = new ActualCar();
int price = new CarDecorator(newCar).GetPrice();

Car在这里的作用很像一个接口,或者一个明确地告诉所有具体装饰器都应该实现GetPrice方法的契约。

Decorator模式的目的是提供一种无需子类化即可扩展类的方法。

"将额外的责任附加到对象动态保持相同的接口。装饰师为用于扩展功能的子类化"(四人帮(

这意味着对于客户端来说,装饰器类型的行为必须与装饰的类型完全相似(模仿(。更重要的是,decorator类型必须可替换为decorated类型。

要使类型可替换,它们必须具有相同的基本类型:

interface IVehicle {}
class Car : IVehicle {}
class Bus : IVehicle {}

现在每个IVehicle都是可替换的:

IVehicle car = new Car();
IVehicle bus = new Bus();
IVehicle vehicle = car;
vehicle = bus;

为了允许decorator类型可替换为decorated类型,两者必须继承相同的基类型。这意味着装饰器将实际扩展装饰的基本类型:

// Common base class. Will be extended by a decorator.
public interface ICar
{
ISound Honk();
//Other properties and methods
}
public class Beagle : ICar 
{
// Implementation of ICar
public ISound Honk() => new BeagleHornSound(); // BeagleHornSound implements ISound
}
// Abstract decorator base class.
// Since the base class implements ICar, every CarDecorator "is-a" ICar.
// This makes CarDecorator and every ICar replaceable and allows the CarDecorator to mimic the decorated/wrapped ICar. 
// Therefore every feature of this class or subclass is actually extending every ICar.
public abstract class CarDecorator : ICar
{
private ICar Car { get; set; }
private CarDecorator(ICar car)
{
this.Car = car;
}
// Implementation of ICar
public ISound Honk() => this.Car.Honk();
}
// Concrete decorator class
public abstract class Lowrider : CarDecorator
{
private Hydraulics Hydraulics { get; set; }

public CarDecorator(ICar car) : base (car)
{
this.Hydraulics = new Hydraulics();
}
public void EnableHydraulic() => LetCarHop();
}

用法

// Extends the ICar by wrapping it into a decorator
public CarDecorator PimpCar(ICar car) 
{
return new Lowrider(car);  
}
ICar beagle = new Beagle(); // Beagle implements ICar
CarDecorator lowrider = PimpCar(beagle); // Returns a Lowrider which extends CarDecorator
// Since the decorator also implements ICar, every CarDecorator is replaceable with every other ICar
ICar pimpedBeagle = lowrider; // Lowrider implements ICar
// Since the decorator "is-a" ICar, it can mimic every ICar
ISound hornSound = lowrider.Honk();
// Since the Lowrider is decorating/wrapping currently a Beagle, it actually mimics a Beagle
bool isSameType = lowrider.Honk() is BeagleHornSound; // true

现在你可以看到,如果装饰器不实现它正在装饰的相同类型,那么你就不会扩展装饰的类型,而是创建了一个新的类型。

您通常通过继承类型并向子类添加新特性来扩展类型。超类(祖先(是扩展的,因为子类(后代(与它的超类(即继承-相同的继承树(仍然是相同的类型
Decorator只是实现相同结果的另一种策略,但不需要对要扩展的类型进行子类化。

装饰器类型(后代(实际上是装饰类型(祖先(的扩展版本。这就像装饰器是装饰类型的子类(扩展(
要在类型层次结构方面实现这一点,装饰器必须与超类具有相同的类型,才能成为真正的子类。基本上,Decorator是在使用组合伪造继承。或者Decorator是一种更灵活的继承形式,因为由单个Decorator封装的每个类型实际上都是在不编写封装类型的新派生类的情况下扩展的。

相关内容

  • 没有找到相关文章

最新更新