大话--装饰者模式

装饰者模式

定义

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

使用场景

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

优点

 装饰类和被装饰类可以独立发展,不会互相耦合。装饰者模式是继承的一个替代模式

通过使用不同的装饰类以及装饰类的排列组合,可以实现不同的效果。

符合开闭原则(OCP):对扩展开放,对修改关闭。  符合多用组合,少用继承原则

缺点

 多层装饰代码较复杂

组成

 组件(Component):每个组件可以单独使用,也可以被装饰者包起来使用。

具体组件(ConcreteComponent):动态地加上新行为的对象,扩展自Component。

装饰者(Decorator):每个装饰者都会包装一个组件,即每个装饰者有一个实例变量保存某个Component的引用。

tips

 装饰者也要实现被装饰对象实现的接口,这样才能使用多态的方法面向接口编程。在被装饰之后依旧返回一个接口引用,使其他类感知不到我们装饰者的存在。

关键代码

 1.Component类充当抽象角色,不应该具体实现。

2.修饰类引用和继承Component类,具体扩展类重写父类方法。

类图

 大话--装饰者模式

使用装饰者模式的源码

 大话--装饰者模式

具体实现

星巴克咖啡订单项目( 咖啡馆):

1) 咖啡种类/单品咖啡:Espresso(意大利浓咖啡 )、ShortBlack 、LongBlack( 美式咖啡 )、Decaf( 无因咖啡 )

2) 调料: Milk、Soy(豆浆)、Chocolate

3) 要求在扩展新的咖啡种类时,具有良好的扩展性、改动方便,维护方便

4)使用 OO 来计算不同种类咖啡的费用 : 客户可以点单品咖啡,也可以单品咖啡+调料组合 。

大话--装饰者模式

 1 package Decorator;
 2 
 3 /**
 4  * @title: Drink
 5  * @Author yzhengy
 6  * @Date: 2020/7/28 23:36
 7  * @Question: 饮料抽象类
 8  */
 9 public  abstract class Drink {
10 
11     public String des;
12     private float price = 0.0f;
13 
14     public String getDes() {
15         return des;
16     }
17 
18     public void setDes(String des) {
19         this.des = des;
20     }
21 
22     public float getPrice() {
23         return price;
24     }
25 
26     public void setPrice(float price) {
27         this.price = price;
28     }
29 
30     //计算费用的抽象方法,需要子类实现
31     public abstract float cost();
32 }
 1 package Decorator;
 2 
 3 /**
 4  * @title: Coffee
 5  * @Author yzhengy
 6  * @Date: 2020/7/28 23:40
 7  * @Question: 缓冲层,由于ConcreteComponent类很多,将共有部分提取出来
 8  */
 9 public class Coffee extends Drink {
10 
11     @Override
12     public float cost() {
13         return super.getPrice();
14     }
15 }
 1 //具体的饮料
 2 public class Espresso extends Coffee {
 3 
 4     public Espresso(){
 5         setDes("意大利咖啡");
 6         setPrice(6.0f);
 7     }
 8 
 9 }
10 
11 public class LongBlack extends Coffee {
12 
13     public LongBlack() {
14         setDes("美式咖啡");
15         setPrice(5.0f);
16     }
17 }
18 
19 public class ShortBlack extends Coffee {
20 
21     public ShortBlack() {
22         setDes("单品咖啡");
23         setPrice(4.0f);
24     }
25 }
 1 package Decorator;
 2 
 3 /**
 4  * @title: Decorator
 5  * @Author yzhengy
 6  * @Date: 2020/7/28 23:45
 7  * @Question: 装饰者对象
 8  */
 9 public class Decorator extends Drink {
10 
11     private Drink obj;
12 
13     public Decorator(Drink obj) {//组合关系
14         this.obj = obj;
15     }
16 
17     @Override
18     public float cost() {
19         return super.getPrice() + obj.cost();//小料自己的价格+单杯咖啡的价格
20     }
21 
22     //obj.getDes():输出被装饰者的信息
23     @Override
24     public String getDes() {
25         return super.des + " "+super.getPrice() + "&&" + obj.getDes();
26     }
27 }
 1 //调料类
 2 package Decorator;
 3 
 4 /**
 5  * @title: Chocolate
 6  * @Author yzhengy
 7  * @Date: 2020/7/29 10:15
 8  * @Question: 具体的decorator ,此处指每一种小料
 9  */
10 public class Chocolate extends Decorator {
11 
12     public Chocolate(Drink obj) {
13         super(obj);//通过子类的构造方法去调用父类的构造方法.
14         setDes("巧克力");
15         setPrice(3.0f);
16     }
17 }
18 
19 public class Milk extends Decorator {
20 
21     public Milk(Drink obj) {
22         super(obj);
23         setDes("牛奶");
24         setPrice(2.0f);
25     }
26 }
27 
28 public class Soy extends Decorator {
29 
30     public Soy(Drink obj) {
31         super(obj);
32         setDes("豆浆");
33         setPrice(1.5f);
34     }
35 }
 1 package Decorator;
 2 
 3 /**
 4  * @title: CoffeeBar
 5  * @Author yzhengy
 6  * @Date: 2020/7/29 10:22
 7  * @Question: 装饰者模式下的订单:两份巧克力+一分牛奶+LongBlack
 8  */
 9 public class CoffeeBar {
10 
11     public static void main(String[] args) {
12         //1.点一份LongBlack
13         Drink order = new LongBlack();
14         System.out.println("费用=" + order.cost());
15         System.out.println("描述=" + order.getDes());
16 
17         //2.order加入一份牛奶
18         order = new Milk(order);
19         System.out.println("加入一份牛奶 费用=" + order.cost());
20         System.out.println("加入一份牛奶 描述=" + order.getDes());
21 
22         //3.order加入一份巧克力
23         order = new Chocolate(order);
24         System.out.println("加入一份牛奶和一份巧克力 费用=" + order.cost());
25         System.out.println("加入一份牛奶和一份巧克力 描述=" + order.getDes());
26 
27         //4.order再加入一份巧克力
28         order = new Chocolate(order);
29         System.out.println("加入一份牛奶和一份巧克力 费用=" + order.cost());
30         System.out.println("加入一份牛奶和一份巧克力 描述=" + order.getDes());
31 
32         //新的订单
33         Drink order2 = new Newcoffee();
34         System.out.println("无因咖啡 费用=" + order2.cost());
35         System.out.println("无因咖啡 描述=" + order2.getDes());
36 
37     }
38 
39 }

如果需要新增加一种咖啡,则只需要增加该咖啡品种即可。

 1 package Decorator;
 2 
 3 /**
 4  * @title: Newcoffee
 5  * @Author yzhengy
 6  * @Date: 2020/7/29 11:19
 7  * @Question: 如果新增了一个咖啡品种
 8  */
 9 public class Newcoffee extends Coffee {
10 
11     public Newcoffee() {
12         setDes("无因咖啡");
13         setPrice(3.5f);
14     }
15 }