一、装饰器模式介绍
装饰器模式(Decorator Pattern),也被称为包装器模式(Wrapper Pattern),是一种结构型设计模式,主要用于在不改变原有对象结构的基础上,动态地给对象增加一些额外的职责或功能。这种模式提供了一种比使用继承更加灵活的替代方案,使得对象的功能扩展变得更加容易和灵活。
1、装饰器模式类图及主要角色
观察者模式类图:
装饰器模式主要包含以下几个角色:
- 抽象构件(Component):定义一个对象接口,可以给这些对象动态地添加一些职责。
- 具体构件(Concrete Component):定义了一个具体的对象,也可以给这个对象添加一些职责。
- 抽象装饰器(Decorator):持有一个构件(Component)对象的引用,并定义一个与抽象构件一致的接口。
- 具体装饰器(Concrete Decorator):负责给构件对象“贴上”附加的职责。
2、应用场景
装饰器模式通常适用于以下场景:
- 动态地给对象添加额外的职责:装饰器模式允许在运行时动态地将新功能附加到对象上,而不需要修改现有的类代码。
- 扩展功能更加灵活:相比于继承,装饰器模式提供了更灵活的扩展方式,避免了类的爆炸性增长。
- 符合开闭原则:装饰器模式可以在不修改现有代码的情况下引入新的装饰器类,从而扩展系统功能。
- 透明地给单个对象添加职责:装饰器模式可以透明地给对象添加职责,而不会影响到其他对象。
3、优缺点
优点:
- 装饰类和被装饰类可以独立发展:装饰器模式使得装饰类和被装饰类可以独立变化,不会相互耦合。
- 动态扩展功能:装饰器模式允许动态地扩展一个实现类的功能,而无需修改现有代码。
- 灵活性高:多个装饰器可以被组合使用,从而创建不同的组合效果,使得系统具有更大的灵活性。
缺点:
- 多层装饰比较复杂:随着装饰器的增多,类的数量也会增加,使得代码变得复杂和难以维护。
- 性能开销:如果过多装饰器嵌套,可能会引入一定的性能开销。
二、实现示例
下面是一个使用Java实现的装饰器模式示例,用于动态地给咖啡添加不同的调料(如糖、牛奶等),而无需为每个调料组合创建一个新的咖啡子类。
首先,我们定义一个咖啡的抽象类(Component):
// 咖啡抽象类
public abstract class Coffee {
String description = "Unknown Coffee";
public String getDescription() {
return description;
}
public abstract double cost();
}
然后,我们创建一个具体的咖啡类(Concrete Component):
// 具体咖啡类:浓缩咖啡
public class Espresso extends Coffee {
public Espresso() {
description = "Espresso";
}
@Override
public double cost() {
return 1.99;
}
}
接下来,我们创建一个装饰器的抽象类(Decorator):
// 咖啡装饰器抽象类
public abstract class CoffeeDecorator extends Coffee {
public abstract String getDescription();
}
现在,我们可以创建具体的装饰器类了,比如加糖(Concrete Decorator):
// 具体装饰器:加糖
public class WithSugar extends CoffeeDecorator {
Coffee coffee;
public WithSugar(Coffee c) {
this.coffee = c;
}
@Override
public String getDescription() {
return coffee.getDescription() + ", with sugar";
}
@Override
public double cost() {
return .10 + coffee.cost();
}
}
再创建一个加牛奶的装饰器(Concrete Decorator):
// 具体装饰器:加牛奶
public class WithMilk extends CoffeeDecorator {
Coffee coffee;
public WithMilk(Coffee c) {
this.coffee = c;
}
@Override
public String getDescription() {
return coffee.getDescription() + ", with milk";
}
@Override
public double cost() {
return .20 + coffee.cost();
}
}
最后,我们可以编写一个测试类来演示装饰器模式的使用:
public class DecoratorPatternDemo {
public static void main(String args[]) {
Coffee espresso = new Espresso();
System.out.println(espresso.getDescription()
+ " $" + espresso.cost());
Coffee darkRoast = new Espresso();
darkRoast = new WithMilk(darkRoast);
darkRoast = new WithSugar(darkRoast);
System.out.println(darkRoast.getDescription()
+ " $" + darkRoast.cost());
}
}
在这个示例中,我们首先创建了一个浓缩咖啡对象,并打印了它的描述和价格。然后,我们创建了一个浓缩咖啡对象,并动态地给它添加了牛奶和糖两种调料,最后打印了加调料后的咖啡描述和价格。这样,我们就可以在不修改现有咖啡类的情况下,通过装饰器模式动态地给咖啡添加不同的调料了。这个设计模式有点像俄罗斯套娃,一层层套起来,在行为组合方面,有很好的灵活性,我们JDK中,文件流也使用了类似模式,大家可有空可以去看看代码。
综上所述,装饰器模式是一种非常有用的设计模式,它提供了一种灵活的方式来扩展对象的功能,同时避免了类的爆炸性增长(其实类的爆炸是转移到了装饰器了)和代码的耦合。
如果对你有用,记得点赞加收藏哦!