Java设计模式学习笔记:装饰器模式

装饰器模式其实比较常见,大家在开发过程中其实经常用到,只不过自己还没发觉自己用到了装饰器这种设计模式,下面通过一个生活中的例子来介绍装饰器模式。

那煎饼果子来说,我们知道煎饼果子有各种配置,加鸡蛋加香肠加生菜加肉等各种豪华配置(bgm:哟哟,切克闹,煎饼果子来一套,我说鸡蛋你说要),我们用代码来体现:

首先是普通的煎饼,不做任何升级的那种,假设5块钱一个:

package com.rq.pattern.decorator.v1;

/**
  * Title: Pancakes
  * Description: 普通煎饼
  * @author RQ 
  * @date 2020年4月12日
 */
public class Pancakes {

	public String getMsg() {
		return "普通煎饼";
	}
	
	public int getPrice() {
		return 5;
	}
	
}

今天想犒劳下自己,加个鸡蛋,那就写一个加一个鸡蛋的煎饼,鸡蛋1块钱:

package com.rq.pattern.decorator.v1;

/**
  * Title: Pancakes
  * Description: 加了一个鸡蛋的煎饼
  * @author RQ 
  * @date 2020年4月12日
 */
public class PancakesWithEgg extends Pancakes{

	public String getMsg() {
		return super.getMsg()+"+1个鸡蛋";
	}
	
	public int getPrice() {
		return super.getPrice()+1;
	}
	
}

如果还想再膨胀一下,再加根香肠,那就写一个加一个鸡蛋一根香肠的煎饼,鸡蛋2块钱:

package com.rq.pattern.decorator.v1;

/**
  * Title: Pancakes
  * Description: 加了一个鸡蛋和香肠的煎饼
  * @author RQ 
  * @date 2020年4月12日
 */
public class PancakesWithEggAndSausage extends PancakesWithEgg{

	public String getMsg() {
		return super.getMsg()+"+1根香肠";
	}
	
	public int getPrice() {
		return super.getPrice()+2;
	}
	
}

运行看一下:

package com.rq.pattern.decorator;

import com.rq.pattern.decorator.v1.Pancakes;
import com.rq.pattern.decorator.v1.PancakesWithEgg;
import com.rq.pattern.decorator.v1.PancakesWithEggAndSausage;

public class TestV1 {

	public static void main(String[] args) {
		
		//普通煎饼
		Pancakes pancakes = new Pancakes();
		System.out.println(pancakes.getMsg()+",总价:"+pancakes.getPrice());
		
		//加了一个鸡蛋的煎饼
		PancakesWithEgg pancakesWithEgg = new PancakesWithEgg();
		System.out.println(pancakesWithEgg.getMsg()+",总价:"+pancakesWithEgg.getPrice());
		
		//加了一个鸡蛋和一根香肠的煎饼
		PancakesWithEggAndSausage pancakesWithEggAndSausage = new PancakesWithEggAndSausage();
		System.out.println(pancakesWithEggAndSausage.getMsg()+",总价:"+pancakesWithEggAndSausage.getPrice());
	}
	
}

结果如下:

普通煎饼,总价:5
普通煎饼+1个鸡蛋,总价:6
普通煎饼+1个鸡蛋+1根香肠,总价:8

看起来没毛病,价格啥算的也都对,but,如果我下次还想再膨胀一下,再加点生菜或者加两个鸡蛋怎么办?如果按照这种方式,我还得再建一个加鸡蛋加香肠加生菜的煎饼对象,或者再建一个只加两个鸡蛋的煎饼对象,这样会导致我们的场景越来越复杂,这显然不是一个正常的写代码的方式。如何解决这个问题呢?重点来了,就是本次要介绍的装饰器模式。

先介绍下装饰器模式的概念:不改变原有对象的基础上,将功能附加到对象上,提供了比继承更有弹性的替代方案。嗯,还是有点抽象,继续举例说明,看看用装饰器模式如何解决我们的煎饼果子需求多的问题。

首先我们得定义一个抽象的煎饼组件,只用来描述煎饼的属性:

package com.rq.pattern.decorator.v2;

/**
  * Title: Pancakes
  * Description: 煎饼抽象化组件,用来定义煎饼对象
  * @author RQ 
  * @date 2020年4月12日
 */
public abstract class Pancakes {

	public abstract String getMsg();
	
	public abstract int getPrice();
	
}

接下来,我们定义基础版的煎饼,即不做任何升级的煎饼:

package com.rq.pattern.decorator.v2;

/**
  * Title: BasePancake
  * Description: 基础版本的煎饼
  * @author RQ 
  * @date 2020年4月12日
 */
public class BasePancakes extends Pancakes{

	@Override
	public String getMsg() {
		return "煎饼";
	}

	@Override
	public int getPrice() {
		return 5;
	}

}

再定义一个煎饼的装饰器:

package com.rq.pattern.decorator.v2;

/**
  * Title: BasePancake
  * Description: 煎饼的装饰器,继承煎饼这个抽象组件
  * @author RQ 
  * @date 2020年4月12日
 */
public class PancakeDecorator extends Pancakes{

	private Pancakes pancakes;
	
	//定义带参数的构造方法,将抽象组件Pancakes传进来,要求下面所有的子类必须实现带参数的构造方法,参数就是抽象组件
	public PancakeDecorator(Pancakes pancakes) {
		this.pancakes = pancakes;
	}
	
	//这里的方法不做任何实现,直接调用传入对象的方法
	@Override
	public String getMsg() {
		return this.pancakes.getMsg();
	}

	@Override
	public int getPrice() {
		return this.pancakes.getPrice();
	}

}

接下来就是根据各种需求,来定义不同的装饰器, 比如鸡蛋装饰器、香肠装饰器、生菜装饰器等等,在定义装饰器的时候,不管是什么,都要求必须继承最初的煎饼装饰器,我们就以鸡蛋装饰器和香肠装饰器来举例说明:

package com.rq.pattern.decorator.v2;

/**
  * Title: BasePancake
  * Description: 加鸡蛋装饰器,继承煎饼的装饰器
  * @author RQ 
  * @date 2020年4月12日
 */
public class EggDecorator extends PancakeDecorator{

	public EggDecorator(Pancakes pancakes) {
		super(pancakes);
	}

	public String getMsg() {
		return super.getMsg()+"加1个鸡蛋";
	}
	
	public int getPrice() {
		return super.getPrice()+1;
	}

}

 

package com.rq.pattern.decorator.v2;

/**
  * Title: BasePancake
  * Description: 加香肠的装饰器,继承煎饼的装饰器
  * @author RQ 
  * @date 2020年4月12日
 */
public class SausageDecorator extends PancakeDecorator{

	public SausageDecorator(Pancakes pancakes) {
		super(pancakes);
	}

	public String getMsg() {
		return super.getMsg()+"加1根香肠";
	}
	
	public int getPrice() {
		return super.getPrice()+2;
	}

}

装饰器建好后,看看如何使用装饰器来组装各种配置的煎饼:

package com.rq.pattern.decorator;

import com.rq.pattern.decorator.v2.BasePancakes;
import com.rq.pattern.decorator.v2.EggDecorator;
import com.rq.pattern.decorator.v2.Pancakes;
import com.rq.pattern.decorator.v2.SausageDecorator;

public class TestV2 {

	public static void main(String[] args) {
		
		//基础版煎饼
		Pancakes pancakes;
		pancakes = new BasePancakes();
		System.out.println(pancakes.getMsg()+",总价:"+pancakes.getPrice());
		
		//加一个鸡蛋的煎饼
		pancakes = new EggDecorator(pancakes);
		System.out.println(pancakes.getMsg()+",总价:"+pancakes.getPrice());
		
		//加一个鸡蛋和香肠的煎饼
		pancakes = new SausageDecorator(pancakes);
		System.out.println(pancakes.getMsg()+",总价:"+pancakes.getPrice());
		
		//只加两个鸡蛋的煎饼
		Pancakes pancakes2 = new BasePancakes();
		pancakes2 = new EggDecorator(pancakes2);
		pancakes2 = new EggDecorator(pancakes2);
		System.out.println(pancakes2.getMsg()+",总价:"+pancakes2.getPrice());
		
	}
}

运行结果:

煎饼,总价:5
煎饼加1个鸡蛋,总价:6
煎饼加1个鸡蛋加1根香肠,总价:8
煎饼加1个鸡蛋加1个鸡蛋,总价:7

对比两种方式,我们就能很清楚的了解了装饰器模式的概念以及使用场景了,以及装饰器模式能帮我们解决的问题。

你可能感兴趣的:(Java设计模式学习笔记)