装饰者模式Decorator(成年程序猿必须懂得一种姿势)—咱们就侃一侃

        装饰者模式是动态地将责任附加上对象上。想要扩展功能,装饰者提供有别于继承的另一种选择,它利用组合和委托在运行时动态地给

组件(被装饰者)加上新的行为,很好的遵循了开放-关闭(对扩展开放,对修改关闭)这一OOP原则。

        我们看下类图,也许就会理解相关的层次结构(时间和精力有限,本文中的有关图形为网上截取的,感兴趣的博友们可以利用一些UML工具画一

画):



        具体一用,我们看看关键代码,可能就能很快理解了。

        如咖啡(组件),需要加各种配料(牛奶、豆浆、摩卡等),每加上不同的配料,价钱就对应的也要上涨,下边就用单纯装模式来实现这个

例子。至于为什么说是用“单纯”的装饰者模式,因为装饰者模式通常配合其他类似的工厂模式或者生成器模式才使其装饰者及被装饰者封装的更好,

处单独用装饰者模式,从而我们能更好的理解它。

代码:

饮料(抽象类,被装饰者)

public abstract class Beverage {
	protected String description = "Unknown Beverage";		//自身描述

	public String getDescription() {
		return description;
	}

	public abstract double cost();                //抽象方法花费
}


具体的饮料(组件,被装饰者),实现抽象方法cost()

public class Espresso extends Beverage {

	public Espresso() {		//无参数构造方法,初始化“描述”变量
		description = "Espresso";
	}

	public double cost() {		//实现抽象方法,返回本身不加任何调料的价钱
		return 1.99;
	}
}


调料(装饰者父类,抽象类)继承被装饰者饮料

public abstract class CondimentDecorator extends Beverage {
	public abstract String getDescription();		//抽象方法,描述自身
}

一个一个的具体调料们(装饰者),继承抽象的父类-调料

public class Mocha extends CondimentDecorator {
	Beverage beverage;	//增加饮料类型的变量,

	public Mocha(Beverage beverage) {          //调料初始化时就指定给哪个饮料(装饰者)加的(装饰谁的)
        this.beverage = beverage;
}

	public String getDescription() {
		return beverage.getDescription() + ", Mocha";           //自己的描述+调用此饮料的方法
	}

	public double cost() {		//自身(装饰者)的价钱+饮料的价钱
		return .20 + beverage.cost();
	}
}

一个一个的具体调料们(装饰者),继承抽象的父类-调料

 
public class Soy extends CondimentDecorator {
	Beverage beverage;

	public Soy(Beverage beverage) {
		this.beverage = beverage;
	}

	public String getDescription() {
		return beverage.getDescription() + ", Soy";
	}

	public double cost() {
		return .15 + beverage.cost();
	}
}


一个一个的具体调料们(装饰者),继承抽象的父类-调料

 
public class Whip extends CondimentDecorator {
	Beverage beverage;

	public Whip(Beverage beverage) {
		this.beverage = beverage;
	}

	public String getDescription() {
		return beverage.getDescription() + ", Whip";
	}

	public double cost() {
		return .10 + beverage.cost();
	}
}


现在我们要喝加各种调料的饮料(没办法,有钱,就是这么任性啊),结账时看看是怎么结账的(so easy!)

public class StarbuzzCoffee {

	public static void main(String[] args) {
		Beverage beverage = new Espresso();	//拿了一杯饮料(组件,即被装饰者)
		System.out.println(beverage.getDescription() + " $" + beverage.cost());

		Beverage beverage2 = new DarkRoast();	//看见没,任性的我们,加了各种调料(被装饰者),看清楚是怎么加吗
		beverage2 = new Mocha(beverage2);
		beverage2 = new Mocha(beverage2);
		beverage2 = new Whip(beverage2);
                /*其调用过程中有点“递归”的感脚,一层到一层,然后到了最底层后,再一层一层叠加数据返回*/
                System.out.println(beverage2.getDescription() + " $" + beverage2.cost());

		Beverage beverage3 = new HouseBlend();
		beverage3 = new Soy(beverage2);
		beverage3 = new Mocha(beverage2);
		beverage3 = new Whip(beverage2);
		System.out.println(beverage3.getDescription() + " $" + beverage3.cost());
	}
}


 

土豪来了,要结账,都闪开,看看账单(输出结果):

%  java StartbuzzCoffee
Espresso $1.99
Dark Roast Coffee, Mocha, Mocha, Mocha, Whip $1.49
House Blend Coffee, Soy, Mocha, Whip $1.34
%

        是不是有点很神奇的样子,是不是很长姿势(别说你长了老汉推车姿势!咱儿要做清纯程序猿,别做骚年程序猿),你们我可不知道,反正我长

了!

        我们看看方法调用的过程的流转过程,如下图:



        我是感觉它很有“递归”姿势。

        装饰者模式动态的将责任附加到对象上,可以一层一层的“装饰”、扩展,提供了比继承更有弹性的替代方案。

        装饰者模式还是要根据特定的情况,如对象由主体+许多可选的部件或者功能构成,纯粹的使用继承或者接口会产生很多类,且很难扩展

的情况。当然,装饰者该做的事,就是能动态地透明地增加行为到被装饰或者包装的对象上,当业务需要窥视装饰者链中的每一个装饰时,

这就超出了它们的“天赋”,就需要慎重考虑考虑了,有些代码会依赖特定的类型,如果这样的代码应用装饰者模式,肯定会带来很多问题,

使代码更加复杂。

        你可以用无数个装饰者包装一个组件,但这些装饰者对组件的客户最好是透明的,这样确实会导致设计中出现很对小对象,就像JDK中

的IO包中的类一样,看的我晕乎乎的,也就像韩国明星一样,大致一看怎么特麽长得一模一样啊(不过现在中国明星也有这个趋势,整容

吗),过度使用,反而会使程序变的复杂,所以是否采用什么时候采用装饰者模式,还是需要慎重考虑、认真考虑滴。

       最后,认真看过的网友们,大神们,如有感觉我这个程序猿有哪个地方说的不对或者不妥或者你有很好的

议或者建议或点子方法,还望您大恩大德施舍n秒的时间留下你的宝贵文字(留言),以便你,我,还有广大的程序猿们更快地成长与进步.......

(如有转载,不胜荣兴!转载请连同复制此区域-作者:Java我人生(陈磊兴) 原文连接:http://blog.csdn.net/chenleixing/article/details/42503877

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值