咕咕咕,托更博主又想起来自己的博客了,今天继续更新设计模式
概述
我们先来看一个快餐店的例子。
快餐店有炒面、炒饭这些快餐,可以额外附加鸡蛋、火腿、培根这些配菜,当然加配菜需要额外加钱,每个配菜的价钱通常不太一样,那么计算总价就会显得比较麻烦。
使用继承的方式存在的问题:
定义:
指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式。
结构
装饰(Decorator)模式中的角色:
- 抽象构件(Component)角色 :定义一个抽象接口以规范准备接收附加责任的对象。
- 具体构件(Concrete Component)角色 :实现抽象构件,通过装饰角色为其添加一些职责。
- 抽象装饰(Decorator)角色 : 继承或实现抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
- 具体装饰(ConcreteDecorator)角色 :实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
案例
我们使用装饰者模式对快餐店案例进行改进,体会装饰者模式的精髓。
类图如下:
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
| public abstract class FastFood { private float price; private String desc;
public FastFood() { }
public FastFood(float price, String desc) { this.price = price; this.desc = desc; }
public void setPrice(float price) { this.price = price; }
public float getPrice() { return price; }
public String getDesc() { return desc; }
public void setDesc(String desc) { this.desc = desc; }
public abstract float cost(); }
public class FriedRice extends FastFood {
public FriedRice() { super(10, "炒饭"); }
public float cost() { return getPrice(); } }
public class FriedNoodles extends FastFood {
public FriedNoodles() { super(12, "炒面"); }
public float cost() { return getPrice(); } }
public abstract class Garnish extends FastFood {
private FastFood fastFood;
public FastFood getFastFood() { return fastFood; }
public void setFastFood(FastFood fastFood) { this.fastFood = fastFood; }
public Garnish(FastFood fastFood, float price, String desc) { super(price,desc); this.fastFood = fastFood; } }
public class Egg extends Garnish {
public Egg(FastFood fastFood) { super(fastFood,1,"鸡蛋"); }
public float cost() { return getPrice() + getFastFood().getPrice(); }
@Override public String getDesc() { return super.getDesc() + getFastFood().getDesc(); } }
public class Bacon extends Garnish {
public Bacon(FastFood fastFood) {
super(fastFood,2,"培根"); }
@Override public float cost() { return getPrice() + getFastFood().getPrice(); }
@Override public String getDesc() { return super.getDesc() + getFastFood().getDesc(); } }
public class Client { public static void main(String[] args) { FastFood food = new FriedRice(); System.out.println(food.getDesc() + " " + food.cost() + "元");
System.out.println("========"); FastFood food1 = new FriedRice();
food1 = new Egg(food1); System.out.println(food1.getDesc() + " " + food1.cost() + "元");
System.out.println("========"); FastFood food2 = new FriedNoodles(); food2 = new Bacon(food2); System.out.println(food2.getDesc() + " " + food2.cost() + "元"); } }
|
好处:
使用场景
当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。
不能采用继承的情况主要有两类:
- 第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;
- 第二类是因为类定义不能继承(如final类)
在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
当对象的功能要求可以动态地添加,也可以再动态地撤销时。
JDK源码解析
IO流中的包装类使用到了装饰者模式。BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter。
我们以BufferedWriter举例来说明,先看看如何使用BufferedWriter
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class Demo { public static void main(String[] args) throws Exception{ FileWriter fw = new FileWriter("C:\\Users\\486\\Desktop\\a.txt"); BufferedWriter bw = new BufferedWriter(fw);
bw.write("hello Buffered");
bw.close(); } }
|
使用起来感觉确实像是装饰者模式,接下来看它们的结构:
小结:
BufferedWriter使用装饰者模式对Writer子实现类进行了增强,添加了缓冲区,提高了写数据的效率。
代理和装饰者的区别
静态代理和装饰者模式的区别:
- 相同点:
- 都要实现与目标类相同的业务接口
- 在两个类中都要声明目标对象
- 都可以在不修改目标类的前提下增强目标方法
- 不同点:
- 目的不同
装饰者是为了增强目标对象
静态代理是为了保护和隐藏目标对象
- 获取目标对象构建的地方不同
装饰者是由外界传递进来,可以通过构造方法传递
静态代理是在代理类内部创建,以此来隐藏目标对象