装饰器模式
为什么使用装饰器模式
应用实例
看到装饰器是在看《Thinking in Java》一书的时候,看到文件读写那边的时候,有提到装饰器模式,同时在文件读写的那一部分,对于各种读入,写出的方式,代码组织结构感觉也是比较怪的,怪的总是吸引人的。
装饰器模式:在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
通过使用装饰器模式,我们可以实现关闭原有代码,开放现有代码的方式来实现更多的功能。通过减少对原有代码的改变,来降低犯错误的几率。不改变妹子的三围,通过装饰不同的制服,实现一个动态扩展,我们就会看到教师,护士,,,其本质功能还是未改变的,只是体验更上一层楼。。。
继续上面的需求来举例子吧,现在我们要针对该服务场所制定一个订单系统,当客户来选择的时候,点一项服务,我们需要向订单中加入一项,然后最后计算一个总和,由于young woman,student,nurse等基础价格是不同的,假设在其基础之上的单项服务价格是相同的,首先我们想到的可能是根据不同的类型继承自一个基类,建立一个类,然后每个作为一个实例,将各项服务作为一个全局变量,然后各项服务有一个set方法,用来改变这些服务的状态,两次调用可以取消该服务,默认各项服务的状态是关闭的,然后最后通过一个cost方法判断各种服务的来计算总价格,当然感觉这是一个很不错的方法。但是由于某种服务的特殊性原因,能提供该服务的人减少,所以该服务价格上涨,或者是在某种服务在一个不小心中诞生,因此,我们需要打开源代码进行添加一些服务,然后需要添加set方法,同时,我们需要对cost进行修改,随着人民思路不断开阔,冒险精神日益增强,各种服务如雨后春笋,我们的维护工作将变得比工作人员还要辛苦了。这个时候,就要引出我们的装饰器模式,我们将所有需要付费的拿出来,因为我们在后期的维护上,就是价格导致的变化给我们带来了困扰,所以如果将这些变化的价格拿出来,单独维护,我们的工作量将会减少。如下结构
//基础抽象类 public abstract class SexService{ String description = "Best Service"; public String getDescription(){ return description; } public abstract int cost(); } //继承自抽象类的本体 public class Nurse extends SexService{ public Nurse(){ description = "You konw"; } public int cost(){ return 150; } } //继承自基础类的用来修饰本体的类 public class PlayXiao extends SexService{ SexService service; public PlayXiao(SexService service){ this.service = service; } public String getDescription(){ return service.getDescription+"PlayXiao"; } public int cost(){ return service.cost+50; } }
调用方式
Nurse sweetHeart = new Nurse(); sweetHeart = new PlayXiao(sweetHeart);
首先我们创建一个本体类,然后将其作为一个实例通过构造函数注入到一个装饰类,在装饰类内部通过委托的形式获得当前的价格和描述,同时由于本体类和装饰类继承自同一个基类,所以可以用来继续向下传递。基础抽象类,通过构造函数进行实例注入,通过委托实现状态,数据更新,从而实现关闭原有代码,开放现有代码。
言归正传,回到正题上来,讲一下其在我们平常开发中的例子
开始也提到了一点关于Java,io库的问题
java I/O库具有两个对称性,它们分别是:
输入-输出对称:比如InputStream 和OutputStream 各自占据Byte流的输入和输出的两个平行的等级结构的根部;而Reader和Writer各自占据Char流的输入和输出的两个平行的等级结构的根部。
byte-char对称:InputStream和Reader的子类分别负责byte和Char流的输入;OutputStream和Writer的子类分别负责byte和Char流的输出
这些作为根类,如果我们想通过缓冲,字节,或者是管道,这个时候我们就需要使用装饰器来进行装饰,然后通过装饰器来实现相应的操作,根类具有read方法,对于装饰类,通过构造函数将基类的一个实例注入进去,然后通过委托模式,首先通过基类的read方法获取字节流,然后根据相应的操作,实现字节读取等。
InputStreamReader input = new InputStreamReader(System.in); BufferedReader reader = new BufferedReader(input); String line = reader.readLine();
下篇更命令模式