装饰器模式

定义

在不改变原有对象的基础之上,将功能附加到对象上;
提供了比继承更有弹性的替代方案(扩展原有对象功能)

适用场景

  • 扩展一个类的功能或给一个类添加附加职责
  • 动态的给一个对象添加功能,这些功能可以再动态的撤销

优点和缺点

优点

  • 继承的有力补充,比继承灵活,不改变原有对象的情况下给一个对象扩展功能;
  • 通过使用不同装饰类以及这些装饰类的排列组合,可以试想不同效果;
  • 符合开闭原则。

缺点

  • 会出现更多的代码,更多的类,增加程序复杂性;
  • 动态装饰时,多层装饰时会更复杂。

结构

  • 抽象构件角色: 定义一个抽象接口以规范准备接收附加责任的对象。
  • 具体构件角色: 实现抽象构件,通过装饰角色为其添加一些职责。
  • 抽象装饰角色: 继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
  • 具体装饰角色: 实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

代码实现

假设我们去买煎饼,一个煎饼8元钱,可以加鸡蛋和香肠,以传统方式来实现,如果用户只是买一个煎饼,我们建一个煎饼类即可实现,如果用户想要加一个鸡蛋,可以新建一个类继承煎饼类来实现,但是如果用户想再加香肠呢?再鸡蛋呢?两个、三个…
很明显,如果再以简单的继承来去实现,我们的类会爆炸式的增加,所以我们可以引入装饰者模式,把鸡蛋和香肠作为装饰,可以动态添加。

首先创建一个抽象构件角色:(煎饼以及作为装饰的抽象类)

1
2
3
4
public abstract class APancakes {
abstract String getDesc();
abstract int cost();
}

具体构件角色:(具体煎饼类,可以有多种煎饼)

1
2
3
4
5
6
7
8
9
10
11
public class Pancakes extends APancakes{
@Override
String getDesc() {
return "煎饼";
}

@Override
int cost() {
return 8;
}
}

抽象装饰角色:(具体装饰角色的抽象类,也可以使用对象类,具体根据业务情况决定)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class AbstractDecorator extends APancakes{

private APancakes aPancakes;

public AbstractDecorator(APancakes aPancakes) {
this.aPancakes = aPancakes;
}

@Override
String getDesc() {
return aPancakes.getDesc();
}

@Override
int cost() {
return aPancakes.cost();
}
}

具体装饰角色:(装饰角色的具体实现)
鸡蛋实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class EggDecorator extends AbstractDecorator {
public EggDecorator(APancakes aPancakes) {
super(aPancakes);
}

@Override
String getDesc() {
return super.getDesc() + " 加一个鸡蛋";
}

@Override
int cost() {
return super.cost() + 1;
}
}

香肠实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class SausageDecorator extends AbstractDecorator {
public SausageDecorator(APancakes aPancakes) {
super(aPancakes);
}

@Override
String getDesc() {
return super.getDesc() + " 加一根香肠";
}

@Override
int cost() {
return super.cost() + 2;
}
}

具体调用:

1
2
3
4
5
6
7
8
9
10
public class Test {
public static void main(String[] args) {
APancakes aPancakes = new Pancakes();
aPancakes = new EggDecorator(aPancakes);
aPancakes = new EggDecorator(aPancakes);
aPancakes = new SausageDecorator(aPancakes);

System.out.println(aPancakes.getDesc()+aPancakes.cost());
}
}

如代码所示,想要加几个鸡蛋或者香肠,可以动态的去实现

结果:

1
煎饼  加一个鸡蛋  加一个鸡蛋  加一根香肠 12

UML类图