Head First(三)--装饰者模式

 本章可以称为“给爱用继承的人一个全新的设计眼界”。本章会学到如何使用对象组合的方式,做到在运行时装饰类。一旦熟悉了装饰的技巧,你将能够在不修改任何底层代码的情况下,给你的(或别人的)对象赋予新的职责。

设计原则:类应该对扩展开放,对修改关闭。


我们先看看对象增强的手段有哪些:

  1. 继承--被增强的对象是固定的,增强的内容也是固定的
  2. 装饰者模式--被增强的对象是可以切换的,增强的内容是固定的
  3. 动态代理--被增强的对象可以切换,增强的内容也可以切换

继承的缺点:

1.增强的内容是死的,不能动

2.被增强的对象也是死的

class 咖啡类 {}

class 有糖咖啡 extends 咖啡类{

}

class 加奶咖啡 extends 咖啡类 {

}

class 加盐咖啡 extends 咖啡类 {

}

如果,加糖又加奶,

class 加糖加奶 extends 加奶 {

}

个性化的需求,使用继承,会导致类的暴增。

--------------------

装饰者模式

1.增强的内容是不能修改的

2.被增强的对象可以是任意的

class 咖啡类 {}

class 有糖咖啡 extends 咖啡类{

}

class 加奶咖啡 extends 咖啡类 {

}

class 加盐咖啡 extends 咖啡类 {

}

咖啡 a = new 加糖();

咖啡 b = new 加盐(a); //对a进行装饰,就是给a加盐。

咖啡 c = new 加盐(b);

装饰者模式在java api IO流用得多。

IO流分类:

1.字节:InputStream, OutputStream

2.字符:Reader, Wirter

InputStream

FileInputStream: 节点流。就是和一个资源绑定在一起的。和磁盘上的文件绑在一起。

BufferedInputStream: 它是装饰流。创建我时一定要给我一个底层对象,我不管你给我的是什么流,我都会给它添加缓冲区。

new BufferedInputStream(任意的InputStream)



ObjectInputStream也是装饰流。


ByteArrayInputStream是一个节点流,它和内存中的一个字节数组绑定在一起


GZIPInputStream是装饰流。

java io中装饰流多,节点流少。

装饰者模式用途:不知道被增强对象的具体类型时,可以用来增强。

BufferedInputStream的作用再解析:你要从BufferedInputStream读一个字节,BufferedInputStream会去磁盘先读一塑料袋的内容,然后,在给你一个字节。你要读第二个字节,BufferedInputStream就不用去磁盘读了,直接给你第二个。这样,就减少了和磁盘的交互。因为,磁盘很慢嘛。

FileInputStream的底层涉及到C的代码,因为要和本地文件系统交互。

BufferedInputStream底层还是要用到FileInputStream,只是,一次拿一塑料袋。

==================================

装饰模式    对新房进行装修并没有改变房屋的本质,但它可以让房子变得更漂亮、更温馨、更实用。在软件设计中,对已有对象(新房)的功能进行扩展(装修)。把通用功能封装在装饰器中,用到的地方进行调用。装饰模式是一种用于替代继承的技术,使用对象之间的关联关系取代类之间的继承关系。引入装饰类,扩充新功能。角色、抽象构件、具体构件、抽象装饰类、具体装饰类。

==================================

装饰者模式可以动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。
该模式的适用环境为:
(1)在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
(2)处理那些可以撤消的职责。
(3)当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
实现该模式的关键步骤:
(1)Component(被装饰对象基类):定义对象的接口,可以给这些对象动态增加职责;
(2)ConcreteComponent(具体被装饰对象):定义具体的对象,Decorator可以给它增加额外的职责;
(3)Decorator(装饰者抽象类):维护指向Component实例的引用,定义与Component一致的接口(也就是要继承或实现被装饰对象基类);
(4)ConcreteDecorator(具体装饰者):具体的装饰对象,给内部持有的具体被装饰对象增加具体的职责;
这样讲大家可能有些不好理解,那我们还是老规矩:
入冬以后天气越来越冷了,下班之后,做为资深吃货,约上二三好友痛快的来场火锅盛宴再爽不过了。说到火锅,不得不提在成都吃过的大龙燚火锅,各种锅底,配菜应有尽有,但我最喜欢的还是大龙燚火锅原味锅底、麻辣牛肉、大刀毛肚、天味香肠、砣砣牛肉、麻辣排骨等,想想都流口水啊。
说道这大家结合装饰者的实现步骤,应该有点感觉了吧,上文提到的锅底,其实就是被装饰对象的基类配料其实就是装饰者抽象类大龙燚火锅原味锅底这些具体的锅底也就是具体的被装饰对象了,麻辣牛肉、大刀毛肚、天味香肠、砣砣牛肉、麻辣排骨这些装饰锅底用的各种配菜也就是具体的装饰对象。说道这,大家应该都豁然开朗了吧,下面我们开始具体的代码实现:

第一步:定义被装饰对象基类(可以是抽象类也可以是接口)

public interface GuoDi {
	float cost();// 锅底当然要有价钱啦
	String name();// 名字也得有哦
}
第二步:定义具体被装饰对象(也就是各种锅底,这里定义两种)
public class YuanYang implements GuoDi {
	@Override
	public float cost() {
		return 48.0f;
	}
	@Override
	public String name() {
		return "鸳鸯锅底";
	}
}
public class DaLongYan implements GuoDi {
	@Override
	public float cost() {
		return 59.0f;
	}
	@Override
	public String name() {
		return "大龙燚火锅原味锅底";
	}
}
第三步:定义装饰者抽象类
public abstract class PeiCai implements GuoDi {
	private GuoDi guodi;
	public PeiCai(GuoDi guodi) {
		this.guodi = guodi;
	}
	@Override
	public float cost() {
		return guodi.cost();
	}
	@Override
	public String name() {
		return guodi.name();
	}
}
第四步:定义具体的装饰者对象
public class MaLaNiuRou extends PeiCai {
	public MaLaNiuRou(GuoDi guodi) {
		super(guodi);
	}
	@Override
	public float cost() {
		return super.cost() + 46f;
	}
	@Override
	public String name() {
		return super.name() + "+麻辣牛肉";
	}
}
public class MaoDu extends PeiCai {
	public MaoDu(GuoDi guodi) {
		super(guodi);
	}
	@Override
	public float cost() {
		return super.cost() + 30f;
	}
	@Override
	public String name() {
		return super.name() + "+大刀毛肚";
	}
}
测试类:
public class Test {
	public static void main(String[] args) {
		GuoDi guodi = new DaLongYan();// 点个大龙燚火锅原味锅底
		MaLaNiuRou y = new MaLaNiuRou(guodi);// 来个麻辣牛肉
		MaoDu x = new MaoDu(y);// 在麻辣牛肉的基础上再来个大刀毛肚
		System.out.println("一共点了:" + x.name() + ",共消费:" + x.cost());
	}
}
输出结果:
一共点了:大龙燚火锅原味锅底+麻辣牛肉+大刀毛肚,共消费:135.0
转自:https://www.cnblogs.com/panhouye/p/6120232.html

看看这两篇把:

http://blog.csdn.net/luanlouis/article/details/19021803

http://blog.csdn.net/jason0539/article/details/22713711

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值