首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件开发 >

读《研磨设计方式》-代码笔记-装饰模式-Decorator

2012-12-26 
读《研磨设计模式》-代码笔记-装饰模式-Decorator声明:本文只为方便我个人查阅和理解,详细的分析以及源代码

读《研磨设计模式》-代码笔记-装饰模式-Decorator
声明:
本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/


import java.io.BufferedOutputStream;import java.io.DataOutputStream;import java.io.FileOutputStream;import java.io.FilterOutputStream;import java.io.IOException;import java.io.OutputStream;/** * 看到书上说是用装饰模式来计算奖金,第一个问题就是:这跟策略模式有什么区别? * 个人理解: * 策略模式一个时刻只能使用一个策略,各种策略之间是平等的 * 装饰模式之间的“装饰”(策略)是相互合作的(例如一种“装饰”基于另一种“装饰”) * 可以使用多个“装饰”,最终各个“装饰”组成一个整体 *  * 对于装饰模式的理解,我认为其实是“组合优于继承”的理念的实现:“装饰”的目的就是为了扩展(或利用)一个类的功能 * 这可通过继承,可使用组合。通常是“组合优于继承” *  * 为了使得“装饰器”之间可嵌套、组合,这些装饰器之间应该有相同的装饰方法:1.继承同一个父类 或者2.实现相同的接口 *//* * 以下代码的业务逻辑:奖金=基本奖金+当月奖金+团队奖金 * 书上是把Component写在抽象类的,我这里写成接口 * bylijinnan */interface IComponent {double calculateBonus(String user);}//基本奖金。默认为0.这个类是被装饰的类,“装饰”从这个类开始class BaseBonusComponent implements IComponent {public double calculateBonus(String user) {return 0;}}abstract class Decorator implements IComponent{protected IComponent component;public Decorator(IComponent component) {this.component = component;}public double calculateBonus(String user) {//you can do something more here...return component.calculateBonus(user);}}//当月奖金class MonthBonusDecorator extends Decorator {public MonthBonusDecorator(IComponent component) {super(component);}//加上当月奖金1000元public double calculateBonus(String user) {return component.calculateBonus(user) + 1000;}}//团队奖金class TeamBonusDecorator extends Decorator {public TeamBonusDecorator(IComponent component) {super(component);}//加上团队奖金2000元public double calculateBonus(String user) {return component.calculateBonus(user) + 2000;}}/* * 扩展:书上提到Java I/O使用了装饰模式 * 业务逻辑:简单地把英文字母向后移动两个位置,例如a->c,c->e...z->b */class EncryptOutputStream extends OutputStream {//持有“被装饰”的对象private OutputStream outputStream;public EncryptOutputStream(OutputStream outputStream) {this.outputStream = outputStream;}@Overridepublic void write(int arg) throws IOException {//做自己的一些处理,相当于“装饰”arg += 2;if (arg > 'z') {arg -= 26;}//调用“被装饰”的对象的方法this.outputStream.write(arg);}/*//下面这样写的话,可实现“装饰器”互换public void close() throws IOException {outputStream.flush();super.close();}*/}class EncryptOutputStream2 extends FilterOutputStream {//private OutputStream outputStream;//这里为什么不再需要持有“被装饰”的对象呢?查看FilterOutputStream源码会发现,FilterOutputStream已经持有了public EncryptOutputStream2(OutputStream outputStream) {super(outputStream);}@Overridepublic void write(int arg) throws IOException {//做自己的一些处理,相当于“装饰”arg += 2;if (arg > 'z') {arg -= 26;}//调用“被装饰”的对象的方法super.write(arg);}}//这个类是用来测试的public class DecoratorPattern {public static void main(String[] args) throws Exception {//测试奖金的计算BaseBonusComponent baseBonus = new BaseBonusComponent();Decorator monthBonus = new MonthBonusDecorator(baseBonus);Decorator teamBonus = new TeamBonusDecorator(monthBonus);/*//装饰的顺序可以改变,写成下面这样也可以Decorator teamBonus = new TeamBonusDecorator(baseBonus);Decorator monthBonus = new MonthBonusDecorator(teamBonus);*/System.out.println(teamBonus.calculateBonus("Tom"));//在这个例子不传递user也可以,但实际应用中每个人的奖金都应该不同//测试“装饰”OutputStream/*  A.当EncryptOutputStream extends OutputStream时,代码中1和2的顺序不可互换  因为out.close时,调用顺序是-->DataOutputStream.close()   -->BufferedOutputStream.close()   -->EncryptOutputStream.close()   -->FileOutputStream.close(),  当执行到BufferedOutputStream.close()时,查看源码有BufferedOutputStream extends FilterOutputStream,  所以BufferedOutputStream继承了FilterOutputStream的close方法,而FileOutputStream.close()会调用flush这个方法,  强制输出缓存的数据(BufferedOutputStream要在8192字节满了才输出)  但当1和2调换过来时,没有内容输出到文件中。  因为,调用顺序是 -->DataOutputStream.close()     -->EncryptOutputStream.close();      EncryptOutputStream.close()会直接调用父类OutputStream.close()(这个方法是个空方法什么也不做)      如果想要1和2可互换,可重写EncryptOutputStream的close方法,调用flush()方法,具体代码见前面(我注释掉了)  B.当EncryptOutputStream2 extends FilterOutputStream时,代码中1和2的顺序可互换    查看FilterOutputStream的close()方法是调用了flush()方法的 */DataOutputStream out = new DataOutputStream(                            new BufferedOutputStream(//1.                            new EncryptOutputStream(//2.        new FileOutputStream("d:/tmp/test.txt"))));out.write("abcdxyz".getBytes());out.close();DataOutputStream out2 = new DataOutputStream(new EncryptOutputStream2(new BufferedOutputStream(new FileOutputStream("d:/tmp/test2.txt"))));out2.write("az".getBytes());out2.close();}}

热点排行