08 装饰者模式(Decorator Pattern)

描述性文字

还记得工厂方法模式中示例代码中的奶茶店吗?在那一节中讲解的是通过工厂方法模式来做奶茶,做奶茶的工作都已经交给小弟了, 小猪的工作量少了很多。于是,写出所有饮品的价格:

奶茶:

  • 原味奶茶:5块
  • 珍珠奶茶:7块
  • 椰果奶茶:7块
  • 珍珠椰果奶茶:9块

柠檬茶:

  • 原味柠檬茶:3块
  • 金桔柠檬茶:5块.

然后顾客要什么点什么,按着菜单收费就好了,然而用户的 需求都是多变的,他们觉得配料那里可以加点红豆,然后你 的菜单需要新增:

  • 红豆奶茶:7块
  • 红豆珍珠奶茶:9块
  • 红豆椰果奶茶:9块
  • 红豆珍珠椰果奶茶:11块

每个组合都写一个,这他么得写多少个,而且用户总是天马行空的,哪天希望配料加点 ,也是有可能的, 每多一种配料,就得增加一堆饮品。我们必须想一个更优的套路,这个时候可以考虑引入装饰者模式, 简单来说就是:一层套一层,比如说要椰果珍珠奶茶:奶茶 –> 套一层珍珠 –> 珍珠(奶茶) –> 套一层椰果 –> 椰果(珍珠(奶茶))逼逼那么多,代码演示下吧!

代码如下

package structPattrn.decoratorPattern;

/**
 * 装饰者模式测试例程
 *     
 * @Package       structPattrn.decoratorPattern
 * @Title:        DecoratorPatternDemo.java
 * @Company:      $
 * @author        BurgessLee 
 * @date          2018年10月16日-下午4:38:01
 * @Description:  $
 */
public class DecoratorPatternDemo {
	
	public static void main(String[] args) {
		Tea mileTea = new MilkTea();
		System.out.println("您点的是:" + mileTea.getName() +" 价格为:"+ mileTea.price());
		
		Tea lemonTea = new LemonTea();
		System.out.println("您点的是:" + lemonTea.getName() +" 价格为:"+ lemonTea.price());
		
		Tea tea3 = new MilkTea();
		System.out.println("您点的是:" + tea3.getName() +" 价格为:"+ tea3.price());
		tea3 = new ZhenZhu(tea3);
		System.out.println("您点的是:" + tea3.getName() +" 价格为:"+ tea3.price());
		tea3 = new YeGuo(tea3);
		System.out.println("您点的是:" + tea3.getName() +" 价格为:"+ tea3.price());
		tea3 = new HongDou(tea3);
		System.out.println("您点的是:" + tea3.getName() +" 价格为:"+ tea3.price());
		tea3 = new JinJu(tea3);
		System.out.println("您点的是:" + tea3.getName() +" 价格为:"+ tea3.price());
	}
	
}

//抽象茶的父类
abstract class Tea{
	private String name = "茶";

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public abstract int price();
}

//定义配料的父类
abstract class Decorator extends Tea{
	public abstract String getName();
}

class MilkTea extends Tea{
	
	public MilkTea() {
		setName("奶茶");
	}

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

class LemonTea extends Tea{
	
	public LemonTea() {
		setName("柠檬茶");
	}

	@Override
	public int price() {
		return 3;
	}
	
}

class ZhenZhu extends Decorator{
	
	private Tea tea;
	
	public ZhenZhu(Tea tea) {
		super();
		this.tea = tea;
	}

	@Override
	public String getName() {
		return "珍珠" + this.tea.getName();
	}

	@Override
	public int price() {
		return 2+ this.tea.price();
	}
	
}

class YeGuo extends Decorator{
	
	private Tea tea;
	
	public YeGuo(Tea tea) {
		super();
		this.tea = tea;
	}

	@Override
	public String getName() {
		return "椰果" + this.tea.getName();
	}

	@Override
	public int price() {
		return 2+ this.tea.price();
	}
	
}

class HongDou extends Decorator{
	
	private Tea tea;
	
	public HongDou(Tea tea) {
		super();
		this.tea = tea;
	}

	@Override
	public String getName() {
		return "红豆" + this.tea.getName();
	}

	@Override
	public int price() {
		return 2+ this.tea.price();
	}
	
}

class JinJu extends Decorator{
	
	private Tea tea;
	
	public JinJu(Tea tea) {
		super();
		this.tea = tea;
	}

	@Override
	public String getName() {
		return "金桔" + this.tea.getName();
	}

	@Override
	public int price() {
		return 2+ this.tea.price();
	}
	
}

打印结果:

您点的是:奶茶 价格为:5
您点的是:柠檬茶 价格为:3
您点的是:奶茶 价格为:5
您点的是:珍珠奶茶 价格为:7
您点的是:椰果珍珠奶茶 价格为:9
您点的是:红豆椰果珍珠奶茶 价格为:11
您点的是:金桔红豆椰果珍珠奶茶 价格为:13

模式要点

定义:


动态的给对象添加一些额外的职责,就增加功能来说,装饰者模式比起生成子类更加灵活!

四个角色:

  1. Component:抽象组件,可以是接口或抽象类,具体组件与抽象装饰类的共同父类,声明了在具体组件中实现的业务方法,可以使客户端以一致的方式处理未修饰对象与修饰后的对象,实现了客户端的透明操作,比如这里的Tea类。
  2. ConcreteComponent:具体组件,实现抽象组件中生命的方法,装饰器类可以给他增加额外的责任(方法),比如这里的MilkTea和LemonTea。
  3. Decorator:抽象装饰类,装饰组件对象的,内部一定要有一个指向组件对象的引用!!!通过该引用可以调用装饰前构建对象的方法,并通过其子类扩展该方法,已达到装饰的目的,比如这里的Decorator类。
  4. ConcreteDecorator:具体装饰类,抽象装饰类的具体实现,可以调用抽象装饰类中定义的方法,也可以新增新的方法来扩充对象的行为。

UML类图

适用场景


装饰者模式是以对客户端透明的方式扩展对象的功能,是继承关系的一种替代方案! 以下情况可以考虑是想用对象组合(组合与委托):在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责;处理那些可以撤消的职责;当不能采用生成子类的方法进行扩充时:一种情况是,可能有大量独立的扩展, 为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类;
 

优缺点

  • 扩展对象功能,比继承灵活,不会导致类个数急剧增加;
  • 可以通过一种动态的方式在运行时选择不同的具体装饰类,从而实现不同的行为;
  • 避免了高层次类有太多的特征,可以从一个最简单的类慢慢给他添加功能;
  • 会产生很多小装饰者对象,会影响性能,过多使用该模式也会使程序变得复杂。

猜你喜欢

转载自blog.csdn.net/Burgess_Lee/article/details/83090869