HeadFirst(三)Decorator 装饰设计模式

 

设计原则

类应该对扩展开发,对修改关闭

不修改现有代码的情况下,可以添加新的行为,这样的设计具有弹性,可以应对变化,提供新的功能。

 

装饰者模式完全遵循开放-关闭的原则

遵循开放-关闭原则,通常会引入新的抽象层次,增加代码的复杂度

应该把注意力集中在主要的容易发生变化的地方,然后应用开放-关闭原则

 

 

装饰:最低层的功能不变,对外提供了更灵活更方便的方法

委托:低层功能调用还得依赖与具有该行为的对象,委托这个对象去完成它自己才能完成的事

 

 

 

咖啡馆的故事


HeadFirst(三)Decorator 装饰设计模式_第1张图片

 

Beverage为所有类的基类,它将作为方法的参数接受各种类型的子类对象

 

HouseBend,DarkRoster,Espresso,Decaf,都是被装饰对象,通过cost方法计算各自的价钱

 

CondimentDecorator继承Beverage,自身为一个抽象类,为子类封装共有的属性和方法

 

Milk,Mocha,Soy,Whip,都是装饰者,将对被装饰对象进行装饰,在内部会让被装饰者去调用自己的方法计算价格

 

 

公共的基类,将来作为方法的参数,接收各种子类对象

package decorator.coffee;

import java.text.NumberFormat;


public abstract class Beverage {

	public static enum BeverageSize {
		BIG, MEDIUM, SMALL;// 大杯,中杯,小杯
	}
	
	//杯子大小
	private BeverageSize size;

	public BeverageSize getSize() {
		return size;
	}

	public void setSize(BeverageSize size) {
		this.size = size;
	}
	
	//饮料描述信息
	protected String description = "Unknow Beverage";

	public String getDescription() {
		return description;
	}
	
	//需由子类去实现去方法
	public abstract double cost();
	
	/**
	 * 计算总价时,加上杯子的钱(只能加1次)
	 * @return
	 */
	public double costTotal() {
		double total = cost();
		if(size!=null) {
			switch (this.size.ordinal()) {
			case 0:
				total += 0.20;//大杯
				break;
			case 1:
				total += 0.15;//中杯
				break;
			case 2:
				total += 0.10;//小杯
				break;
			}
		}
		NumberFormat nf = NumberFormat.getInstance();
		nf.setMaximumFractionDigits(2);
		return Double.valueOf(nf.format(total));
	}
}

 

将要被装饰的类(一)

package decorator.coffee;


public class Espresso extends Beverage {
	
	public Espresso() {
		this.description = "Espresso";
	}

	@Override
	public double cost() {
		return 1.99;
	}

}

 

 将要被装饰的类(二)

package decorator.coffee;


public class HouseBlend extends Beverage {
	
	public HouseBlend() {
		this.description = "HouseBlend";
	}

	@Override
	public double cost() {
		return 0.89;
	}

}

 

 

中转作用的类,实现装饰者与被装饰者都是Beverage的子类

package decorator.condiment;

import decorator.coffee.Beverage;

/**
 * 继承Beverage,让装饰者继承它,这样装饰者(调料)与被装饰者(具体的饮料)都属于Beverage
 * 都是Beverage的子类,从而在面向父类/接口编程时,都可以作为参数传入到方法中!
 */
public abstract class CondimentDecorator extends Beverage {
	
	//持有祖先的引用
	//通过祖先获取旁系,祖先对子孙的设计,这样便可以利用多态的功能,动态绑定子类对象了!
	//【这里的做法与javascript中getParentNode()获取sibing的思想有一丁点儿的类似】
	Beverage beverage;//实为组合的应用,特殊的地方:被组合的对象为自己的父类
	
	public CondimentDecorator(Beverage beverage) {
		this.beverage = beverage;//参数为父类,为多态做准备
	}
	
	
	@Override
	public String getDescription() {
		return this.beverage.getDescription()+", "+this.getClass().getSimpleName();
	}

}

 

装饰者(一)

package decorator.condiment;

import decorator.coffee.Beverage;

/**
 * 真正的装饰者
 *
 */
public class Mocha extends CondimentDecorator {
	
	public  Mocha(Beverage beverage) {
		super(beverage);//将实际的coffee传进来
	}
	

	@Override
	public double cost() {
		return 0.20 + this.beverage.cost();//delegate委托beverage的具体实现类去计算自己的价钱
	}
	
}

 

装饰者(二)

package decorator.condiment;

import decorator.coffee.Beverage;

/**
 * 真正的装饰者
 *
 */
public class Soy extends CondimentDecorator {
	
	public  Soy(Beverage beverage) {
		super(beverage);//将实际的coffee传进来
	}
	

	@Override
	public double cost() {
		return 0.40 + this.beverage.cost();//delegate委托beverage的具体实现类去计算自己的价钱
	}
	
}

 

装饰者(三)

package decorator.condiment;

import decorator.coffee.Beverage;

/**
 * 真正的装饰者
 *
 */
public class Whip extends CondimentDecorator {
	
	public  Whip(Beverage beverage) {
		super(beverage);//将实际的coffee传进来
	}
	

	@Override
	public double cost() {
		return 0.30 + this.beverage.cost();//delegate委托beverage的具体实现类去计算自己的价钱
	}
	
}

 

 

 

测试

package test;

import decorator.coffee.Beverage;
import decorator.coffee.Beverage.BeverageSize;
import decorator.coffee.Espresso;
import decorator.condiment.Mocha;

public class BeverageTest {
	public static void main(String[] args) {
		
		Beverage beverage = new Espresso();
		System.out.println(beverage.getDescription()+" $"+beverage.costTotal());
		
		beverage = new Mocha(beverage);
		System.out.println(beverage.getDescription()+" $"+beverage.costTotal());
		beverage = new Mocha(beverage);
		System.out.println(beverage.getDescription()+" $"+beverage.costTotal());
		
		//设置杯子的大小
		beverage.setSize(BeverageSize.BIG);
		
		System.out.println(beverage.getDescription()+" $"+beverage.costTotal());
		
	}
}

 

 

 

JAVA I/O中对装饰者模式的应用

 


HeadFirst(三)Decorator 装饰设计模式_第2张图片
 


HeadFirst(三)Decorator 装饰设计模式_第3张图片
 

你可能感兴趣的:(Decorator)