# 装饰器模式(Decorator Pattern)
代码地址
- Github:DesignPattern/src/main/java/com/design/decorator (opens new window)
- Gitee(码云):DesignPattern/src/main/java/com/design/decorator (opens new window)
# 1. 介绍
装饰器模式允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装,这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能
在软件开发过程中,有时想用一些现存的组件。这些组件可能只是完成了一些核心功能。但在不改变其结构的情况下,可以动态地扩展其功能。所有这些都可以釆用装饰器模式来实现
# 1.1. 特点
- 装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用
- 通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果
- 装饰器模式完全遵守开闭原则
# 1.2. 结构
- 抽象构件(Component):定义一个抽象接口以规范准备接收附加责任的对象
- 具体构件(ConcreteComponent):实现抽象构件,通过装饰角色为其添加一些职责
- 抽象装饰(Decorator):继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能
- 具体装饰(ConcreteDecorator):实现抽象装饰的相关方法,并给具体构件对象添加附加的责任
# 1.3. 优缺点
- 意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活
- 主要解决:我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀
- 何时使用:在不想增加很多子类的情况下扩展类
- 如何解决:将具体功能职责划分,同时继承装饰者模式
- 关键代码: Component 类充当抽象角色,不应该具体实现。修饰类引用和继承 Component 类,具体扩展类重写父类方法
- 优点
- 装饰类和被装饰类可以独立发展,不会相互耦合
- 是继承的一个替代模式
- 可以动态扩展一个实现类的功能
- 缺点
- 多层装饰比较复杂,会增加许多子类,过度使用会增加程序得复杂性
# 1.4. 举例
- 在现实生活中,常常需要对现有产品增加新的功能或美化其外观,如房子装修、相片加相框等,都是装饰器模式
- 比如吃面,有汤面,炒面,面可以加配菜装饰,煎蛋,卤蛋,牛肉等,但是不管怎么加配菜,都还是一份面
# 2. 代码
用吃面的例子,模式结构:抽象构件、具体构件、抽象装饰、具体装饰
# 2.1. 抽象构件
/**
* 面条抽象构件
*
* @author wliduo[i@dolyw.com]
* @date 2022/1/18 16:30
*/
public interface NoodleComponent {
/**
* 备注
*
* @param
* @return java.lang.String
* @throws
* @author wliduo[i@dolyw.com]
* @date 2022/1/18 16:31
*/
String remark();
/**
* 价格
*
* @param
* @return java.lang.Integer
* @throws
* @author wliduo[i@dolyw.com]
* @date 2022/1/18 16:31
*/
Integer price();
}
# 2.2. 具体构件
/**
* 炒面具体构件
*
* @author wliduo[i@dolyw.com]
* @date 2022/1/18 16:30
*/
public class FryNoodleConcreteComponent implements NoodleComponent {
@Override
public String remark() {
return "炒面10快";
}
@Override
public Integer price() {
return 10;
}
}
/**
* 汤面具体构件
*
* @author wliduo[i@dolyw.com]
* @date 2022/1/18 16:30
*/
public class SoupNoodleConcreteComponent implements NoodleComponent {
@Override
public String remark() {
return "汤面8快";
}
@Override
public Integer price() {
return 8;
}
}
# 2.3. 抽象装饰
/**
* 配菜抽象装饰
*
* @author wliduo[i@dolyw.com]
* @date 2022/1/18 16:40
*/
public abstract class AbstractSideDishDecorator implements NoodleComponent {
private NoodleComponent noodleComponent;
public AbstractSideDishDecorator(NoodleComponent noodleComponent) {
this.noodleComponent = noodleComponent;
}
@Override
public String remark() {
return noodleComponent.remark();
}
@Override
public Integer price() {
return noodleComponent.price();
}
}
# 2.4. 具体装饰
/**
* 牛肉具体装饰
*
* @author wliduo[i@dolyw.com]
* @date 2022/1/18 16:44
*/
public class BeefConcreteDecorator extends AbstractSideDishDecorator {
public BeefConcreteDecorator(NoodleComponent noodleComponent) {
super(noodleComponent);
}
@Override
public String remark() {
return super.remark() + " 加份牛肉5快";
}
@Override
public Integer price() {
return super.price() + 5;
}
}
/**
* 煎蛋具体装饰
*
* @author wliduo[i@dolyw.com]
* @date 2022/1/18 16:44
*/
public class FriedEggConcreteDecorator extends AbstractSideDishDecorator {
public FriedEggConcreteDecorator(NoodleComponent noodleComponent) {
super(noodleComponent);
}
@Override
public String remark() {
return super.remark() + " 加份煎蛋3快";
}
@Override
public Integer price() {
return super.price() + 3;
}
}
/**
* 卤蛋具体装饰
*
* @author wliduo[i@dolyw.com]
* @date 2022/1/18 16:44
*/
public class MarinatedEggConcreteDecorator extends AbstractSideDishDecorator {
public MarinatedEggConcreteDecorator(NoodleComponent noodleComponent) {
super(noodleComponent);
}
@Override
public String remark() {
return super.remark() + " 加份卤蛋2快";
}
@Override
public Integer price() {
return super.price() + 2;
}
}
# 2.5. 执行
/**
* 装饰器模式
* 通过不同的装饰器自由组合
* 我们可以灵活的组装出各式各样的面加配菜
* 这正是装饰者模式的优点
* 但明显可以看出代码变复杂了
*
* @author wliduo[i@dolyw.com]
* @date 2022/1/18 16:05
*/
public class Main {
public static void main(String[] args) {
// 汤面
NoodleComponent soupNoodleConcreteComponent = new SoupNoodleConcreteComponent();
// 加牛肉
soupNoodleConcreteComponent = new BeefConcreteDecorator(soupNoodleConcreteComponent);
// 加煎蛋
soupNoodleConcreteComponent = new FriedEggConcreteDecorator(soupNoodleConcreteComponent);
System.out.println(soupNoodleConcreteComponent.remark());
System.out.println(soupNoodleConcreteComponent.price());
System.out.println("----------------------");
// 炒面
NoodleComponent fryNoodleConcreteComponent = new FryNoodleConcreteComponent();
// 加牛肉
fryNoodleConcreteComponent = new BeefConcreteDecorator(fryNoodleConcreteComponent);
// 加卤蛋
fryNoodleConcreteComponent = new MarinatedEggConcreteDecorator(fryNoodleConcreteComponent);
System.out.println(fryNoodleConcreteComponent.remark());
System.out.println(fryNoodleConcreteComponent.price());
System.out.println("-----------------------");
// 炒面
NoodleComponent fryNoodleConcreteComponentEasy = new FryNoodleConcreteComponent();
// 加牛肉加卤蛋加煎蛋
fryNoodleConcreteComponentEasy =
new BeefConcreteDecorator(
new MarinatedEggConcreteDecorator(new FriedEggConcreteDecorator(fryNoodleConcreteComponentEasy)));
System.out.println(fryNoodleConcreteComponentEasy.remark());
System.out.println(fryNoodleConcreteComponentEasy.price());
}
}
输出
汤面8快 加份牛肉5快 加份煎蛋3快
16
----------------------
炒面10快 加份牛肉5快 加份卤蛋2快
17
-----------------------
炒面10快 加份煎蛋3快 加份卤蛋2快 加份牛肉5快
20