我正在学习设计模式教程,并遇到了装饰模式。我知道如何以及何时使用装饰器模式,但是,对于为什么需要从组件派生装饰器,我有点困惑。
我看到的例子如下所示:
//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--一种关系类型。因此,我看了很少的例子,并意识到这是如何设计的装饰模式。
我不想质疑为什么装饰器模式是这样设计的,我只想知道为什么没有装饰器模式是从组件包装中派生出来的。
发布于 2020-08-05 11:39:53
Decorator模式的目的是提供一种不用子类来扩展类的方法。
“将额外的责任附加到动态保持相同接口的对象上,装饰器为扩展功能提供了一种灵活的子类选择。(四人集团)
这意味着对于客户端,装饰器类型的行为必须完全类似于(模仿)修饰类型。更重要的是,装饰器类型必须可替换为装饰类型。
若要使类型可替换,它们必须具有相同的基类型:
interface IVehicle {}
class Car : IVehicle {}
class Bus : IVehicle {}现在,每个IVehicle都是可替换的:
IVehicle car = new Car();
IVehicle bus = new Bus();
IVehicle vehicle = car;
vehicle = bus;若要允许装饰类型与装饰类型可替换,两者都必须继承相同的基类型。这意味着装饰师实际上将扩展装饰的基本类型:
// 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是一种更灵活的继承形式,因为由单个装饰器包装的每个类型实际上都是扩展的,而不需要编写包装类型的新派生类。
发布于 2020-08-04 18:25:37
您的CarDecorator是一个基本装饰器,它应该继承Car接口(这里是一个抽象类),以确保CarDecorator已经实现(应该覆盖) GetPrice方法。
如果CarDecorator不继承Car,那么您就不能这样做:
Car newCar = new ActualCar();
int price = new CarDecorator(newCar).GetPrice();Car在这里提供的服务很像一个接口,或者是一个契约,它明确地告诉所有具体的装饰者都应该实现GetPrice方法。
https://stackoverflow.com/questions/63252693
复制相似问题