设计模式12:装饰者模式

装饰者模式

装饰器模式是一种用于代替继承的技术,无需通过继承增加子类就能扩展对象的新功能。使用对象的关联关系代替继承关系,更加灵活,同时避免类型体系的快速膨胀。

怎么说?老样子,先设想个场景

假如我要去楼下买手抓饼吃,一般来说,手抓饼都会提供不同的配料,比如加鸡蛋,加鸡柳,加肉松或者加火腿,不同的配料价钱也不同

是不是感觉饿啦哈哈哈哈,我们继续...

如果我们要用编程语言来描述的话,我们首先想到的就是先定义一个基类,然后每增加一种搭配就写个子类

定义一个手抓饼基类,啥都没加的那种

public class HandPanCake {
	
	String name;
	
	public HandPanCake(String name) {
		this.name = name;
	}
	
	public void eatSense(){
		
		System.out.println("啥都没加,难吃的一匹");
	}

如果我们要增加配料,比如要加个蛋的话,我们继承手抓饼类进行拓展

class HandPanCakeWithEgg extends HandPanCake{

	public HandPanCakeWithEgg(String name) {
		super(name);
		
	}
	//增加配料
	public void addEgg(){
		System.out.println("加了鸡蛋,美滋滋");
	}
	
	public void eatSense(){
		super.eatSense();
		addEgg();
	}	
}

同样,我们也可以类似分别写出增加 鸡柳、肉松、火腿等的搭配。到目前为止的话,都没什么问题

但是,如果某天我捡到钱了,于是买手抓饼的时候同时打算增加鸡蛋和火腿这两样的组合(就是又加鸡蛋又加火腿啦),那么现在要怎么操作呢?是不是同样用继承的方式呢? 如果我又打算加鸡蛋和肉松,是不是又要写个子类呢?再换一种包含多个配料的组合的搭配,则又要再写个子类,这样的话,如果我们的搭配非常多,则需要建立非常多的子类,显然这不是我们想要看到的结果,所以我们就提出了新的思路,而这种思路,就是我们要讲的装饰者模式

再小小的总结下,装饰者模式解决的是组合搭配搭配问题,当独立搭配(单独加鸡柳、单独加鸡蛋,单独加..)数量增加时,其组合搭配数量是爆炸式增长的...

主要角色

  • Component抽象构件角色。真实对象和装饰对象有相同的接口。这样,客户端对象就能够以与真实对象相同的方式同装饰对象交互。
  • ConcreteComponent 具体构件角色(真实对象):
  • Decorator装饰角色:持有一个抽象构件的引用。装饰对象接受所有客户端的请求,并把这些请求转发给真实的对象。这样,就能在真实对象调用前后增加新的功能。
  • ConcreteDecorator具体装饰角色:负责给构件对象增加新的责任。

实例讲解

首先定义一个抽象的手抓饼接口,里面定义了吃的感觉这一方法

public interface IhandPanCake {
	
	void eatSense();

}

接着是实现手抓饼接口,构建真实对象(是一个啥都没加的裸饼)

//真实角色,实现抽象接口
public class HandPanCake implements IhandPanCake{
	
	public void eatSense(){
		
		System.out.println("啥都没加,难吃的一匹");
	}

}

再也就是装饰者角色,同样也是实现手抓饼接口,该角色持有一个抽象构建的引用,负责把请求转发给真实角色

public class HandPanCakeDecorator implements IhandPanCake{
	
	
	protected IhandPanCake handPanCake;
	
	public HandPanCakeDecorator(IhandPanCake handPanCake) {
		super();
		this.handPanCake = handPanCake;
	}

	@Override
	public void eatSense() {
		handPanCake.eatSense();
	}

}

接下来就是定义具体的装饰角色了,分别负责把鸡蛋、火腿这些增加到具体的手抓饼上

加蛋

public class HandPanCakeWithEgg extends HandPanCakeDecorator{

	public HandPanCakeWithEgg(IhandPanCake handPanCake) {
		super(handPanCake);
		
	}
	
	public void addEgg(){
		System.out.println("加了鸡蛋,美滋滋");
	}
	
	public void eatSense() {
		super.eatSense();
		addEgg();
	}

}

加鸡柳

public class HandPanCakeWithChicken extends HandPanCakeDecorator{

	public HandPanCakeWithChicken(IhandPanCake handPanCake) {
		super(handPanCake);
	}
	
	public void addChicken(){
		System.out.println("加了鸡柳,吃了流口水");
	}
	
	public void eatSense() {
		super.eatSense();
		addChicken();
	}

}

加火腿

public class HandPanCakeWithHam extends HandPanCakeDecorator{

	public HandPanCakeWithHam(IhandPanCake handPanCake) {
		super(handPanCake);
	}
	
	public void addHam(){
		System.out.println("加了火腿,有点爽");
	}
	
	public void eatSense() {
		super.eatSense();
		addHam();
	}

}

客户端测试

采用装饰者模式的话,当我们要增加多种组合的搭配时,就不需要增加新的子类了,而是

		HandPanCake handPanCake = new HandPanCake();
		handPanCake.eatSense();
		
		System.out.println("老板,加个鸡柳和蛋..................");
		
		HandPanCakeWithChicken handPanCakeWithChickenAndEgg = new HandPanCakeWithChicken(handPanCakeWithEgg);
		handPanCakeWithChickenAndEgg.eatSense();

当然也可以用set方法来组装装饰类

优点

  • 扩展对象功能,比继承灵活,不会导致类个数急剧增加
  • 可以对一个对象进行多次装饰,创造出不同行为的组合,得到功能更加强大的对象具体构建类和具体装饰类可以独立变化
  • 用户可以根据需要自己增加新的具体构件子类和具体装饰子。

缺点

  • 产生很多小对象。大量小对象占据内存,一定程度上影响性能。
  • 装饰模式易于出错,调试排查比较麻烦。

实际开发中的应用

  • IO中输入流和输出流的设计(最典型)
  • Servlet API 中提供了一个request对象的Decorator设计模式的默认实现类HttpServletRequestWrapper,HttpServletRequestWrapper 类,增强了request对象的功能。

桥接模式与装饰模式

这两个模式似乎有点像?两个模式都是为了解决子类过多问题, 但他们的诱因不同:

1.桥接模式对象自身有 沿着多个维度变化的趋势 , 本身不稳定;

2.装饰者模式对象自身非常稳定, 只是为了增加新功能/增强原功能。 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值