四、装饰者模式

装饰者模式

装饰者模式拥有一个设计非常巧妙的结构,它可以动态添加对象功能,在基本的设计原则中,有一条重要的设计准则,叫做合成、聚合复用原则,根据该原则的思想,代码复用应该尽可能的使用委托,而不是使用继承,因为继承是一种紧密耦合,任何父类的改动都会影响子类,不利于系统维护,而委托则是松散耦合,只要接口不变,委托类的改动并不会影响其上层对象。
装饰者模式就充分利用了这种思想,通过委托机制,复用系统中的各个组件,在运行时,可以将这些功能组件进行叠加,从而构造一个超级对象,使其拥有所有这些组件的功能,而各个子功能模块被很好的维护在各个组件的相关类中,拥有整洁的系统结构。
装饰者模式可以有效分离性能组件和功能组件,从而提升模块的可维护性并增加模块的复用性。
装饰者模式结构
装饰者和被装饰者拥有相同的接口,被装饰者通常是系统的核心组件,完成特定的功能目标,而装饰者则可以在被装饰者的方法前后,加上特定的前置处理和后置处理,增强被装饰者的功能。
装饰者模式角色
装饰者一个典型的案例就是对输出结果进行增强,比如,现在需要将某一结果通过HTML进行发布,那么首先需要将内容转化为一个HTML文本,同时由于内容需要在网络上通过HTTP流传,故还需要为其增加HTTP头,当然,作为一个更复杂的情况,可能还要为其安置TCP头等。
装饰者模式的核心思想在于:无需将所有的逻辑,核心内容构建、HTML文本构造HTTP头生成等3个功能模块粘合在一起实现,通过装饰者模式,可以将它们分解为3个几乎完全独立的组件,并在使用时灵活的进行装配,为了实现这个功能
装饰者模型示例
IPacketCreator即装饰接口,用于处理具体内容,PacketBodyCreator是具体的组件,它的功能是构造要发布信息的核心内容,但是它不负责将其构造成一个格式工整、可直接发布的数据格式。PacketHTTPHeaderCreator负责对给定的内容加上HTTP头部,PacketHTMLHeaderCreator负责将给定的内容格式化成HTML文本。3个功能模块相对独立且分离,易于系统维护。

IPacketCreator的实现很简单,它是一个单方法的接口:
interface IPacketCreator {
	//用于内容处理
	String handleContent();
}

PacketBodyCreator用于返回数据包的核心数据:
public class PacketBodyCreator implements IPacketCreator{
	@Override
	public String handleContent() {
		//返回核心数据但不包括格式
		return "Content of Packet";
	}
}

PacketDecorator维护核心组件component对象,它负责告知子类,其核心业务逻辑应该全权委托
component完成,自己仅仅做增强处理。
public abstract class PacketDecorator implements IPacketCreator{
	IPacketCreator component=null;
	public PacketDecorator(IPacketCreator c) {
		component=c;
	}
}

PacketHTMLHeaderCreator是具体的装饰类,它负责对核心发布的内容进行HTML格式化操作。需要特别
注意的是,它委托了具体组件cmponent进行核心业务处理。
public class PacketHTMLHeaderCreator extends PacketDecorator{

	public PacketHTMLHeaderCreator(IPacketCreator c) {
		super(c);
	}
	//将给定的数据封装成HTML
	@Override
	public String handleContent() {
		StringBuffer sb=new StringBuffer();
		sb.append("<html>");
		sb.append("<body>");
		sb.append(component.handleContent());
		sb.append("</body>");
		sb.append("</html>");
		return sb.toString();
	}
}

PacketHTTPHeaderCreator与PacketHTMLHeaderCreator类似,但是它完成数据包HTTP头部的处理,
其余业务处理依然交由内部的component完成。
public class PacketHTTPHeaderCreator extends PacketDecorator{

	public PacketHTTPHeaderCreator(IPacketCreator c) {
		super(c);
	}
	//对给定的数据加上HTTP头信息
	@Override
	public String handleContent() {
		StringBuffer sb=new StringBuffer();
		sb.append("Cache-Control:no-cache\n");
		sb.append("Date:Mon,31Dec201904:25:57GMT\n");
		sb.append(component.handleContent());
		return sb.toString();
	}
}

对于装饰者模式正常值得关注的就是它的使用方法:在本例中通过层层构造和组装这些装饰者和被装饰者到一个
对象中,使其有机的结合在一起工作。
public class Demo{
	public static void main(String[] args) throws Exception {
		IPacketCreator pc=new PacketHTTPHeaderCreator(
							new PacketHTMLHeaderCreator(
							new PacketBodyCreator()));
		System.out.println(pc.handleContent());
	}
}
结果:
Cache-Control:no-cache
Date:Mon,31Dec201904:25:57GMT
<html><body>Content of Packet</body></html>

可以看到通过装饰者的构造函数,将被装饰者对象传入,作为核心组件PacketBodyCreator最先被构造,
其次PacketHTMLHeaderCreator,最后才是PacketHTTPHeaderCreator。
这是顺序表示,首先由PacketBodyCreator对象去生成核心发布内容,接着由PacketHTMLHeaderCreator
对象对内容进行处理,将其转化为HTML,最后由PacketHTTPHeaderCreator对HTML安置HTTP头部。

在JDK的实现中,有不少组件也是用装饰者模式实现,其中一个最典型的例子就是OutputStream和InputStream类族的实现。以OutputStream为例,OutputStream提供的方法比较简单,功能也比较弱,但通过各种装饰者增强,OuputStream可以被赋予强大的功能。
装饰者模式在OutputStream的应用
系统的核心类,实现了向文件写入数据,使用DataOuputStream可以在FileOutputStream的基础上,增加对多种数据类型的写操作支持,而BufferOuputStream装饰器,可以对FileOutputStream增加缓冲功能,优化IO性能,以BufferedOuputStream为代表的性能组件,是将性能模块和功能模块分离的一种典型实现。

public class Demo{
	public static void main(String[] args) throws Exception {
		DataOutputStream dout=new DataOutputStream(
				new BufferedOutputStream(
						new FileOutputStream("d:\\a.txt")));
		//没有缓冲流的对象
		DataOutputStream dout2=new DataOutputStream(
						new FileOutputStream("d:\\a.txt"));
	}
}
有缓冲流拥有更好的实现方式。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值