装饰器模式的主要用途是在不改变原有代码的情况下,动态地为对象新增新的功能。这种模式可以避免在原有对象的基础上进行代码修改和扩展,从而保持代码的灵活性和可维护性。
装饰器模式通常涉及以下几个角色:
- 1.抽象组件(Component):
定义了一个抽象接口,被装饰的对象和新添加的功能都要实现该接口。
- 2.具体组件(ConcreteComponent):
实现了抽象组件接口的具体对象,被装饰的对象。
- 3.抽象装饰器(Decorator):
继承了抽象组件接口,同时持有一个抽象组件类型的引用,用于装饰原有对象。
- 4.具体装饰器(ConcreteDecorator):
实现了抽象装饰器接口,具体实现对原有对象的装饰。
示例:
示例的目的是不修改类 BasicCar 的情况下,使用装饰器类 LeatherSeatsDecorator 来扩展其功能。
步骤一,创建一个被装饰的接口 ICar,这是抽象组件:
public interface ICar
{
// 描述
string GetDescription();
// 费用
int GetCost();
}
步骤二,创建一个具体的类 BasicCar,实现 ICar 接口,这是具体组件:
public class BasicCar : ICar
{
// 描述
public string GetDescription()
{
return "普通车";
}
// 费用
public int GetCost()
{
return 10000;
}
}
步骤三,创建一个抽象装饰器类 CarDecorator,它也实现 ICar 接口,它持有一个 ICar 类型的引用:
public abstract class CarDecorator : ICar
{
protected ICar car;
public CarDecorator(ICar car)
{
this.car = car;
}
public virtual string GetDescription()
{
return car.GetDescription();
}
public virtual int GetCost()
{
return car.GetCost();
}
}
步骤四,创建具体装饰器 LeatherSeatsDecorator,它继承自抽象装饰器 CarDecorator 并添加额外的功能,实现具体的装饰逻辑:
public class LeatherSeatsDecorator : CarDecorator
{
public LeatherSeatsDecorator(ICar car) : base(car)
{
}
// GetDescription 新的行为
public override string GetDescription()
{
return car.GetDescription() + ", 添加了真皮座椅";
}
// GetCost 新的行为
public override int GetCost()
{
return car.GetCost() + 2000;
}
}
现在,我们就可以使用 LeatherSeatsDecorator 来装饰 BasicCar,并添加新的行为:
//装饰前
ICar car = new BasicCar();
Console.WriteLine("装饰前描述: " + car.GetDescription());
Console.WriteLine("装饰前花费: #34; + car.GetCost());
//装饰 car
car = new LeatherSeatsDecorator(car);
Console.WriteLine("装饰后描述: " + car.GetDescription());
Console.WriteLine("装饰后花费: #34; + car.GetCost());
输出结果:
装饰前描述: 普通车
装饰前花费: $10000
装饰后描述: 普通车, 添加了真皮座椅
装饰后花费: $12000
如图:
通过装饰器模式,将 BasicCar 对象包装在 LeatherSeatsDecorator 中,并添加额外的行为和属性,而不必修改原有的类结构。这样,我们可以动态地添加、组合不同的装饰器,以扩展和定制对象的功能。
总结:
使用装饰器模式,可以使代码更加灵活,有助于实现单一职责原则,使代码的新增功能维持在独立的装饰器中,避免了代码的冗余和重复修改。装饰器模式还可以动态地给一个对象添加多个装饰器,实现复杂的功能组合。