一、什么时候使用装饰者模式
公司门口有一个小摊卖鸡蛋饼和肉夹馍的,有时候早上吃早餐就回去光顾一下那个小摊,点了鸡蛋饼之后往往还可以在这个基础之上增加一些配料,例如煎蛋、火腿片、生菜,每个配料额价格都不一样,不管你怎么配配料,最终价格是鸡蛋饼基础价加上每一种所选配料价格的总和.小摊的价格单如下:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNvwVZ2x2bzNXak9CX90TQNNkRrFlQKBTSvwFbslmZvwFMwQzLcVmepNHdu9mZvwFVywUNMZTY18CX052bm9CX6lFROd3aE1kMNpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2LcRHelR3LcJzLctmch1mclRXY39zMxUTOxQTN0EzNygDM4EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
现在有这么一个问题,不同的主体早餐加上不同的配料有不同的价钱,怎样实现了?
大多数人的第一印象可能想到的是会使用继承.
1.首先定义一个早餐基类
2.对于加煎蛋、火腿片、肉松、黄瓜丝的,分别写一个子类继承
3.对于加煎蛋又加火腿片的写一个类、对于加煎蛋又加肉松的又写一个类、对于加煎蛋又加黄瓜丝的又写一个类等
说到这里,你会发现这里四种配料就要写十几种实现类了,那如果我们的配料是二十几种或者三十几种呢,那么使用继承这种方式肯定会使我们的子类爆炸,那么要怎么解决了,答案就是使用装饰者模式.(主体是鸡蛋饼或肉夹馍,配料是煎蛋、火腿片、肉松、黄瓜丝)
二、什么是装饰者模式
装饰者模式是在已有功能的基础上,动态地添加更多功能的一种方式,这些新加的代码装饰了原有类的 核心职责或主要行为。
三、什么是装饰者模式
看看具体java代码是怎么实现的:
早餐基类(被装饰者)
public abstract class Pancake {
public String desc = "我不是一个具体的饼";
public String getDesc() {
return desc;
}
public abstract double price();
}
鸡蛋饼类(被装饰者的初始状态,有些自己的简单装饰)
public class TornCake extends Pancake {
public TornCake() {
desc = "鸡蛋饼";
}
@Override
public double price() {
return 4;
}
}
肉夹馍类(被装饰者的初始状态,有些自己的简单装饰)
public class Roujiamo extends Pancake {
public Roujiamo() {
desc = "肉夹馍";
}
@Override
public double price() {
return 6;
}
}
配料的基类(装饰者,用来对早餐基类进行多层装饰,每层装饰增加一些配料)
public abstract class Condiment extends Pancake {
public abstract String getDesc();
}
煎蛋(装饰者的第一层)
public class FiredEgg extends Condiment {
private Pancake pancake;
public FiredEgg(Pancake pancake) {
this.pancake = pancake;
}
@Override
public String getDesc() {
return pancake.getDesc() + ", 煎蛋";
}
@Override
public double price() {
return pancake.price() + 2;
}
}
火腿片(装饰者的第二层)
public class Ham extends Condiment {
private Pancake pancake;
public Ham(Pancake pancake) {
this.pancake = pancake;
}
@Override
public String getDesc() {
return pancake.getDesc() + ", 火腿片";
}
@Override
public double price() {
return pancake.price() + 1.5;
}
}
肉松(装饰者的第三层)
public class DriedMeatFloss extends Condiment{
private Pancake pancake;
public DriedMeatFloss(Pancake pancake) {
this.pancake = pancake;
}
@Override
public String getDesc() {
return pancake.getDesc() + ", 肉松";
}
@Override
public double price() {
return pancake.price() + 1;
}
}
黄瓜丝(装饰者的第四层)
public class YellowCucumberSilk extends Condiment{
private Pancake pancake;
public YellowCucumberSilk(Pancake pancake){
this.pancake = pancake;
}
@Override
public String getDesc() {
return pancake.getDesc() + ", 黄瓜丝";
}
@Override
public double price() {
return pancake.price() + 0.5;
}
}
测试类
public class MyTest {
public static void main(String[] args) {
Pancake tornCake = new TornCake();
//鸡蛋饼基础价
System.out.println(String.format("%s ¥%s", tornCake.getDesc(), tornCake.price()));
Pancake roujiamo = new Roujiamo();
roujiamo = new FiredEgg(roujiamo);
roujiamo = new FiredEgg(roujiamo);
roujiamo = new Ham(roujiamo);
roujiamo = new DriedMeatFloss(roujiamo);
roujiamo = new YellowCucumberSilk(roujiamo);
//我好饿
System.out.println(String.format("%s ¥%s", roujiamo.getDesc(), roujiamo.price()));
}
}
结果
四、装饰者模式优缺点
优点:
1、装饰者模式可以提供比继承更多的灵活性
2、可以通过一种动态的方式来扩展一个对象的功能、在运行时选择不同的装饰器,从而实现不同的行为.
3、通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。
4、具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。
缺点:
1、会产生很多的小对象,增加了系统的复杂性
2、这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。
参考博客:https://blog.csdn.net/qq_38157516/article/details/79852804