`

读《研磨设计模式》-代码笔记-装饰模式-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;
	}
	
	@Override
	public 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);
	}
	
	@Override
	public 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();
	}

}

2
2
分享到:
评论

相关推荐

    研磨设计模式源码

    《研磨设计模式源码》是一份非常宝贵的资源,它提供了设计模式的实践代码,帮助开发者深入理解并应用这些模式。设计模式是软件工程中经过长期实践总结出来的一套通用解决方案,它们描述了在特定场景下如何解决常见...

    研磨设计模式-part2

    第22章 装饰模式(Decorator) 第23章 职责链模式(Chain of Responsibility) 第24章 桥接模式(Bridge) 第25章 访问者模式(Visitor) 附录A常见面向对象设计原则 附录BUML简介 参考文献

    研磨设计模式-part4

    第22章 装饰模式(Decorator) 第23章 职责链模式(Chain of Responsibility) 第24章 桥接模式(Bridge) 第25章 访问者模式(Visitor) 附录A常见面向对象设计原则 附录BUML简介 参考文献

    研磨设计模式-part3

    第22章 装饰模式(Decorator) 第23章 职责链模式(Chain of Responsibility) 第24章 桥接模式(Bridge) 第25章 访问者模式(Visitor) 附录A常见面向对象设计原则 附录BUML简介 参考文献

    研磨设计模式 源代码

    《研磨设计模式》是一本深入探讨软件设计模式的经典书籍,源代码包含了书中所讲解的各种设计模式的实际应用示例。设计模式是软件工程中的重要概念,它们是经过反复验证、在特定情境下解决常见问题的有效解决方案。...

    C++设计模式--基于Qt4开源跨平台开发框架

    结构型模式如适配器模式(Adapter)、装饰器模式(Decorator)和代理模式(Proxy),则关注如何组合和连接类与对象,以达到新的功能。行为型模式如观察者模式(Observer)、策略模式(Strategy)和访问者模式...

    设计模式精解-GoF-23种设计模式解析--附C++源代码

    - 装饰模式(Decorator):动态地给一个对象添加一些额外的职责。 - 享元模式(Flyweight):使用共享对象,有效地支持大量细粒度的对象。 3. **行为型模式**:这类模式关注对象之间的责任分配。 - 责任链模式...

    研磨设计模式(完整带书签).part2.pdf

    第22章 装饰模式(Decorator) 第23章 职责链模式(Chain of Responsibility) 第24章 桥接模式(Bridge) 第25章 访问者模式(Visitor) 附录A常见面向对象设计原则 附录BUML简介 参考文献

    Java设计模式之-Decorator装饰模式

    Decorator模式,也称为装饰模式,是设计模式中的一个重要组成部分,它在不改变原有对象接口的前提下,动态地给对象添加新的功能,从而扩展了对象的能力。这篇博客()将深入探讨这个模式的细节。 装饰模式的核心...

    设计模式专题之(七)装饰模式---设计模式装饰模式示例代码(python--c++)

    总结一下,装饰模式是一种强大的设计模式,它允许我们在运行时动态地给对象添加新的功能,而无需修改对象的原有代码。在Python中,我们可以利用装饰器这一特性轻松实现;而在C++中,通过继承和多态,我们可以构建一...

    c++设计模式-结构型模式-装饰器模式

    c++设计模式-结构型模式-装饰器模式;QT工程;c++简单源码; 装饰器(Decorator)模式的定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。

    设计模式--装饰者模式java例子

    装饰者模式是软件设计模式中的一种结构型模式,它的主要目的是动态地给对象添加新的功能,而无需修改原有代码。在Java中,装饰者模式通常通过继承和组合来实现,它提供了一种比继承更灵活的方式来扩展对象的功能。...

    java设计模式---诙谐易懂版

    代理模式(Proxy Pattern)、单例模式(Singleton Pattern)、工厂方法...装饰模式(Decorator Pattern)、迭代器模式(Iterator Pattern)、组合模式(Composite Pattern)、观察者模式(Observer Pattern)、责任链...

    研磨设计模式PDF

    装饰器模式(Decorator)允许动态地给对象添加新的行为或责任;代理模式(Proxy)为对象提供一个代理以控制对这个对象的访问;桥接模式(Bridge)将抽象部分与实现部分分离,使它们可以独立变化;组合模式...

    通过C#实现设计模式-装饰模式(DecoratorPattern).rar

    装饰模式(Decorator Pattern)是一种结构型设计模式,它允许你向一个现有的对象添加新的功能,同时又不改变其结构。装饰模式通过创建一个装饰类,该类包装了原始类的实例,并在调用原始类方法之前或之后添加额外的...

    设计模式之 Decorator模式和代码实现

    【Decorator模式】是一种设计模式,它允许在运行时动态地给对象...在实际的软件开发中,Decorator模式同样适用于那些需要动态增减功能的对象,例如在UI设计中添加装饰元素,或者在数据库连接池中添加不同的连接策略等。

    vue脚手架,vue3 组件 vue-property-decorator 组件

    `vue-property-decorator`是一个库,它是Vue.js和TypeScript的结合,提供了装饰器来帮助我们在TypeScript中更好地声明和管理组件的属性。它使得我们可以利用TypeScript的强类型系统,提高代码的可维护性和可读性。...

    《设计模式--基于C#的工程化实现及扩展》.(王翔)_《0528》.rar

    结构型模式关注如何将对象和类组合成更大的结构,如适配器模式(Adapter)、装饰器模式(Decorator)和代理模式(Proxy)等,它们提供了更好的抽象和接口集成。行为型模式则关注对象之间的交互和职责分配,如策略...

    23个设计模式图解--学习笔记

    在《23个设计模式图解--学习笔记》中,我们探讨了这些模式,以便于理解和应用到实际开发中。以下是这23个设计模式的详细说明: 1. **工厂方法**(Factory Method):定义一个用于创建对象的接口,让子类决定实例化...

Global site tag (gtag.js) - Google Analytics