设计模式之装饰者模式案例学习

转载请注明出处:http://blog.csdn.net/droyon/article/details/8630106

装饰者模式:顾名思义将对象装饰的更加漂亮,只是更漂亮,他还是他,没有改变类型。

官方定义:动态的将责任附加到对象上。若要扩展功能,装饰着提供了比继承更有弹性的替代方案。

案例情景:

煎饼果子(pancake),包含一个鸡蛋、一个脆饼。我们可以选择加辣椒(pepper),可以选择加香肠(Sausage),可以选择多加鸡蛋(Eggs)。(上地软件园路上的煎饼果子,你懂的!)

我们要实现对每一个煎饼果子进行描述。例如:”煎饼果子、不要辣椒“

我们如果为每一个煎饼果子都构建一个类,比如 PancakeWithPepper、PancakeWithSausage,那么我们就制造了一个维护的噩梦,比如如果多加一个蛋,可以写PancakeWithONeEggs、那么多加俩蛋那、仨蛋那?PancakeWithThreeEggs?

装饰着模式可以很好的解决这类问题。

源代码下载

Pancake.java//煎饼果子

public class Pancake {
	public Pancake() {
	};
	public String toString(){
		return "[煎饼:一个鸡蛋,一个脆饼--4元一个]";
	}
	public int cost(){
		return 4;
	}
}

DecoratorEggs.java//装饰者,用鸡蛋装饰煎饼果子

public class DecoratorEggs extends Pancake{
	Pancake mPancake;
	private int mEggsCount;
	public DecoratorEggs(Pancake p,int count){
		mPancake = p;
		mEggsCount = count;
	}
	@Override
	public String toString() {
		return mPancake.toString() + "[+"+mEggsCount+"个鸡蛋--1元1个]";
	}
	@Override
	public int cost() {
		return mPancake.cost()+1*mEggsCount;
	}
	
}

DecoratorPepper.java//装饰者,加辣椒

public class DecoratorPepper extends Pancake{
	Pancake mPancake;
	public DecoratorPepper(Pancake p){
		mPancake = p;
	}
	@Override
	public String toString() {
		return mPancake.toString()+"[放辣椒]";
	}
	@Override
	public int cost() {
		return mPancake.cost();
	}
	
}

DecoratorSausage.java//装饰者,香肠装饰煎饼果子

public class DecoratorPepper extends Pancake{
	Pancake mPancake;
	public DecoratorPepper(Pancake p){
		mPancake = p;
	}
	@Override
	public String toString() {
		return mPancake.toString()+"[放辣椒]";
	}
	@Override
	public int cost() {
		return mPancake.cost();
	}
	
}
DecoratorTest.java//测试类

public class DecoratorTest {
	public static void main(String args[]){
		Pancake pancake = new Pancake();//一个普通煎饼
		System.out.println(pancake+"价格:"+pancake.cost());
		
		Pancake decoratorEggs = new DecoratorEggs(pancake, 2);//多加两个鸡蛋,用鸡蛋装饰煎饼
		System.out.println(decoratorEggs+"价格:"+decoratorEggs.cost());
		
		DecoratorPepper decoratorEggsAndPepper = new DecoratorPepper(decoratorEggs);//用两个鸡蛋装饰之后哦再用辣椒装饰它
		System.out.println(decoratorEggsAndPepper+"价格:"+decoratorEggsAndPepper.cost());
		
		Pancake pancakeWithEggsWithPepperWithSausage = new DecoratorSausage(decoratorEggsAndPepper);//继续装饰,用香肠装饰
		System.out.println(pancakeWithEggsWithPepperWithSausage+"价格:"+pancakeWithEggsWithPepperWithSausage.cost());
		
		DecoratorSausage decoratorSausage = new DecoratorSausage(new DecoratorEggs(new DecoratorPepper(new Pancake()), 1));//另外一个煎饼
		decoratorSausage.setSausage(2);
		System.out.println(decoratorSausage+"价格:"+decoratorSausage.cost());
		
	}
}

测试结果:

[煎饼:一个鸡蛋,一个脆饼--4元一个]价格:4
[煎饼:一个鸡蛋,一个脆饼--4元一个][+2个鸡蛋--1元1个]价格:6
[煎饼:一个鸡蛋,一个脆饼--4元一个][+2个鸡蛋--1元1个][放辣椒]价格:6
[煎饼:一个鸡蛋,一个脆饼--4元一个][+2个鸡蛋--1元1个][放辣椒][加0根香肠--2元一根]价格:6
[煎饼:一个鸡蛋,一个脆饼--4元一个][放辣椒][+1个鸡蛋--1元1个][加2根香肠--2元一根]价格:9


总结:

继承可以扩展类的功能,但不见得是最好的方案。继承可以从父类那里得到定义好的属性和方法,但继承在实现起来不具备弹性。继承的行为是在编译时就决定好的,而且所有的子类都继承得到相同的行为。组合可以扩展对象的行为,在运行时动态的进行扩展。利用组合维护代码,通过动态的改变组合对象,可以实现不需要改变代码添加新功能的行为。

开放关闭原则:类应该对扩展开放,对修改关闭。---设计原则

在不需要改变代码的情况下,扩展类的行为。比如观察者模式,通过加入新的观察者,不需要修改主题的代码,我们可以在任何时候扩展类的行为。
装饰者对象和被装饰的对象拥有相同的超类型,也就是说,装饰之后,被装饰对象的类型不能变。这样在任何时候就可以通过新的装饰者装饰它。


在java语言中,我们看到的io操作,也就是流,他们也是装饰者对象的例子。InputStream可以读取字节,然后显示,BufferedInputStream包装了InputStream,将InputStream读取的内容放在缓冲区中,在读取结束后,一起显示。


你可能感兴趣的:(设计模式)