0. 目录
1. 介绍
1.1 装饰器模式的介绍
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
创建了一个装饰类 去包装原有的类 在不改变 要扩展的类的前提下 提供额外功能。
1.2 适用的场景
比如有些场景,我们使用 继承的方式实现扩展,会出现类爆炸 的问题。
例如:
我现在这个面馆,有炸酱面,麻酱面。
那么我只需要定义一个抽象的面条类,
和继承面条类的炸酱面类,和麻酱面类。
这样看是没有问题。
那么需求变更来了:
现在面馆说:我现在面条可以加醋,可以加辣椒,可以两个都加。
那么为了不更改之前的代码,想,唉?这个容易,我们在扩展(3 * 2)个类不就行了。一个加醋的炸酱面,一个加辣椒的炸酱面,一个加醋和辣椒的炸酱面,然后再把这个炸酱面换成麻酱面,这又是三个类,加起来6个了。但是你想想,面馆又推出了一款面条,叫刀削面,你看看,这就9个了,如果扩展了个调料,这类写起来就更多 了,这类的个数。增加的很快。这就产生了类爆炸的问题。
此时 就引出了这个装饰模式。此模式可以解决此问题。避免类爆炸,同时还符合ocp原则。
总的来说何时使用?
- 动态地给一个对象添加一些额外的职责
- 并且在不想增加很多子类的情况下扩展类。
1.3 优点
装饰类和被装饰类可以独立发展,不会相互耦合
装饰模式可以动态扩展一个实现类的功能。
1.4 缺点
看起来比较复杂,不容易理解,而且,这里面有一个继承并不符合is a 的关系。
2. 类图
3. 代码(不重要)
3.1 Nooldes
/**
* 面条统称抽象类
* @author immortal
*/
abstract class Noodles {
// 面条的描述
private String description;
public Noodles(String description) {
this.description = description;
}
/**
* 获取价格的方法,子类去实现
*/
public abstract Double getPrice();
/**
* 获取描述
*/
public String getDescription() {
return this.description;
}
}
3.2 Noodles 的实现 炸酱面类
/**
* 炸酱面,为了方便理解,再加上英语不太好诠释,
* 所以这边使用拼音缩写
* @author immortal
*
*/
class ZjNoodles extends Noodles {
/**
* 父类没有无参构造,所以这边调用的是其有参构造
* @param description
*/
public ZjNoodles() {
super("炸酱面");
}
/**
* 确定价格。7块钱,香香香
*/
@Override
public Double getPrice() {
return 7d;
}
}
3.3 Noodles 的实现 麻酱面类
/**
* 麻酱面,为了方便理解,这边使用的拼音, 英语也不好写
* @author immortal
*
*/
class MjNoodles extends Noodles {
/**
* 父类没有无参构造,所以这边调用的是其有参构造
* @param description
*/
public MjNoodles() {
super("麻酱面");
}
/**
* 确定价格。5块钱,我感觉这价格,我能接受。哈哈
*/
@Override
public Double getPrice() {
return 5d;
}
}
3.4 调料的抽象类 (Spice)
/**
* 面条调料抽象类,比如有 醋,辣椒, 大蒜啥的
* 注意,这里是重点,这里虽然调料跟面条不是is a 的关系,
* 看似不太象是能拥有继承关系,但是这个设计模式就是这样。
*
* @author immortal
*
*/
abstract class Spice extends Noodles {
// 重点:聚合一个Noodles,并且继承一个Noodles
// 继承的目的就是为了,装饰了这个noodles之后,其类型还是一个noodles
// 聚合的的目的,就是为了获取 要装饰的源类
protected Noodles noodles;
public Spice(Noodles noodles) {
super("面条调料");
this.noodles = noodles;
}
/**
* 获取价格,子类来实现
*/
public abstract Double getPrice();
}
3.5 调料的实现类- 醋(Vinegar)
/**
* 醋, 可以给面条放醋,继承调料
* @author immortal
*/
class Vinegar extends Spice {
public Vinegar(Noodles noodles) {
super(noodles);
}
/**
* 这边拿到父类的 Noodles, 进行价格装饰,加醋是1块钱
*/
@Override
public Double getPrice() {
return super.noodles.getPrice() + 1.0;
}
/**
* 对面条进行描述的装饰,因为加了醋
*/
@Override
public String getDescription() {
return super.noodles.getDescription() + "加 醋";
}
}
3.6 调料的实现类- 辣椒
/**
* 辣椒, 可以给面条放醋,继承调料
* @author immortal
*
*/
class Chilli extends Spice {
public Chilli(Noodles noodles) {
super(noodles);
}
/**
* 加辣椒,多给1.5块钱
*/
@Override
public Double getPrice() {
return super.noodles.getPrice() + 1.5;
}
/**
* 装饰原有的 添加上描述
*/
@Override
public String getDescription() {
return super.noodles.getDescription() + "加了 辣椒";
}
}
3.7 使用方法
public static void main(String[] args) {
// 1. 来个炸酱面
Noodles zjNoodles = new ZjNoodles();
System.out.println(zjNoodles.getDescription());
System.out.println(zjNoodles.getPrice());
// 2. 给炸酱面放点醋
Noodles zjVinegarNoodles = new Vinegar(zjNoodles);
System.out.println(zjVinegarNoodles.getPrice());
System.out.println(zjVinegarNoodles.getDescription());
// 3. 醋不够,再放点
Noodles zjVinegarNoodles2 = new Vinegar(zjVinegarNoodles);
System.out.println(zjVinegarNoodles2.getPrice());
System.out.println(zjVinegarNoodles2.getDescription());
// 4. 放点辣椒。。。。。可以层层包装下去
}
4. 是否满足ocp?(如何扩展)
5. 总结
自己记录一下学习,写的很烂,也不会表达。。。。。。。