天天看点

通俗详细讲解装饰者设计模式-设计模式-结构型1、场景直入2、解决方案3、具体代码4、升华总结5、源码解析

目录

1、场景直入

2、解决方案

3、具体代码

4、升华总结

(1)装饰者模式定义:

(2)使用场景:

(3)优点:

(4)缺点:

5、源码解析

1、场景直入

有一个煎饼果子类,

动态需求有加一个蛋、加两个蛋、加辣椒、加葱、加香菜、还有加香肠火腿等等。不同的需求对应了不同的价格。

那我们如果针对每一种需求,都声明一个煎饼果子的子类,那需要多少类?

煎饼加一个蛋类、煎饼加一个香肠类、煎饼加两个蛋类、煎饼加两个蛋两个香肠类。。。学过排列组合的老师出来一下!

可以看到,单纯使用继承,在类似场景中会导致类的数目爆炸式增长。

2、解决方案

核心是把蛋、香肠、辣椒等这些需求都单独建立类,然后再和煎饼果子基础类产生组合,组合后保证产生的类还得是煎饼果子类。这就像一个人穿的衣服,长裙、短裙、裤子衬衫就像人的装饰,人始终是主体,一个人穿上漂亮的短裙还是人吗?当然是。穿上超短裤还是人吗?当然是。不穿呢?。。。

首先,有一个煎饼果子抽象类AbstractBatterCake

然后,再来一个装饰抽象类AbstractDecorator,该类继承自煎饼果子抽象类AbstractBatterCake,保证任何的装饰之后,得到的仍然是煎饼果子类。另外,构造方法的参数也要是煎饼果子抽象类,即从哪个类的基础上进行装饰,这样保证了装饰类的连续可动态叠加。

其次,依次具体化实现装饰抽象类AbstractDecorator。

通俗详细讲解装饰者设计模式-设计模式-结构型1、场景直入2、解决方案3、具体代码4、升华总结5、源码解析

3、具体代码

https://github.com/phs999/DesignPatterns/tree/4f98c1fc8e1ab5cbc53533305907fd24c5ca6cca/design_pattern/src/structural/decorator/v2

一定要先看关键的测试类:

package structural.decorator.v2;

public class Test {
	public static void main(String[] args) {
		AbstractBatterCake batterCake;
		batterCake=new BatterCake();
		batterCake=new EggDecorator(batterCake);
		batterCake=new EggDecorator(batterCake);
		batterCake=new SausageDecorator(batterCake);
		System.out.println(batterCake.getDesc()+" 销售价格:"+batterCake.price());
	}
	
}
           

然后是抽象煎饼类:

package structural.decorator.v2;

//抽象煎饼类
public abstract class AbstractBatterCake {
	
	protected abstract String getDesc();
	
	protected abstract int price();
}
           

基本煎饼子类: 

package structural.decorator.v2;

//煎饼
public class BatterCake extends AbstractBatterCake{
	@Override
	protected String getDesc() {
		return "煎饼";
	}
	@Override
	protected int price() {
		return 8;
		
	}
}
           

装饰抽象类: 

package structural.decorator.v2;

public abstract class AbstractDecorator extends AbstractBatterCake{
	
	private AbstractBatterCake battercake;
	
	public AbstractDecorator(AbstractBatterCake batterCake) {
		this.battercake=batterCake;
	}
	
	//public abstract void dosomthing();
	
	@Override
	protected String getDesc() {
		return this.battercake.getDesc();
	}

	@Override
	protected int price() {
		return this.battercake.price();
	}

}
           

加蛋装饰类:

package structural.decorator.v2;
//加蛋 装饰
public class EggDecorator extends AbstractDecorator{

	public EggDecorator(AbstractBatterCake batterCake) {
		super(batterCake);
	}

	@Override
	protected String getDesc() {
		return super.getDesc()+"加一个鸡蛋";
	}

	@Override
	protected int price() {
		return super.price()+1;
	}
	
	

}
           

香肠装饰类: 

package structural.decorator.v2;
//加香肠 装饰
public class SausageDecorator extends AbstractDecorator{

	public SausageDecorator(AbstractBatterCake batterCake) {
		super(batterCake);
	}

	@Override
	protected String getDesc() {
		return super.getDesc()+"加一根香肠";
	}

	@Override
	protected int price() {
		// TODO Auto-generated method stub
		return super.price()+2;
	}
	
	

}
           

4、升华总结

我们从代码中看到,在基础的煎饼类上我们可以不断的叠加装饰,使之具有更加丰富的料。但是,当前的装饰类只是进行了对煎饼基本方法的重写。当然,我们可以在装饰类中新增新的方法,使得煎饼拥有更加丰富的特性。

(1)装饰者模式定义:

在不改变原有对象的基础之上,将功能附加到对象上。

提供了比继承更有弹性的替代方案(扩展原有对象功能)。

(2)使用场景:

扩展一个类的功能或给一个类添加附加职责

动态的给一个类添加功能,这些功能可以再动态的撤销。

(3)优点:

继承的有力补充,比继承灵活,不改变原有对象的情况下给一个对象扩展功能。

可以将多个类中重复的功能代码单独拿出来,实现复用,降低基础类的复杂性。

通过使用不同的装饰类以及这些装饰类的排列组合,可以实现不同的效果。

符合开闭原则。

(4)缺点:

会出现更多的代码,更多的类,增加程序复杂性。

动态装饰时、多层装饰时会更复杂。比如在煎饼果子的基础上,现在又有了包子、面条等食物,这样就会更加复杂,不过这不是设计模式本身带来的复杂性,是业务逻辑复杂后引起的代码复杂性。

另外,你也可以参考 装饰者模式在坦克大战代码中的应用 ,文章中对装饰者模式进行了总结,并且对实际应用中遇到的一些问题和注意事项作了介绍。

5、源码解析

比如我们看Java IO中的BufferedReader,该类继承自Reader抽象类,同时在该类中使用带参构造参数Reader,传入修饰前的类。

通俗详细讲解装饰者设计模式-设计模式-结构型1、场景直入2、解决方案3、具体代码4、升华总结5、源码解析
通俗详细讲解装饰者设计模式-设计模式-结构型1、场景直入2、解决方案3、具体代码4、升华总结5、源码解析

同样,我们也可以看到BufferedInputStream与InputStream之间的关系。