学习笔记之装饰者模式

学习笔记之装饰者模式

在讨论装饰者模式之前我们先来说一下继承和组合

尽管继承威力巨大,但是它并不是总能实现最有弹性最好维护的设计,但是通过组合和委托可以在运行时具有继承行为的效果。利用继承设计子类的行为,是在编译时静态决定的,而且所有的子类都会继承到相同的行为。然而,如果能够利用组合的做法扩展对象的行为,就可以在运行时动态的进行扩展。通过动态的组合对象,可以写新的代码添加新的功能,而无需修改现有的代码。既然没有改变现有的代码,那么引起bug和意外副作用的机会将大幅减少。

所以代码应该如同晚霞中的莲花一样地关闭(免于改变),如同晨曦中的莲花一样开放(能够扩展)这也引出了一个开放-关闭设计原则:对扩展开放对修改关闭。

接下来认识装饰者模式

首先讨论一个例子,星巴克咖啡

 



如果按照这个类图来写的话,真是类爆炸,这不仅违反了面向接口编程而不面向实现编程的原则,还违反了多用组合少用继承的原则。真是事倍功半,超级麻烦并且代码也是超级的烂,保证你写完绝对不会再去想看第二眼,简直是一个维护噩梦,但是想一想还有没有更好的方法,如果你了解了观察者模式,简直是所有的问题都解决了

我们可以以饮料为主题,然后在运行时以调料来“装饰”饮料。

下面展示几张图片你就理解了

 



从图上我们可以得到

1. 装饰者和被装饰者具有相同的类型

2. 你可以用一个或多个装饰者包装一个对象

3. 既然装饰者和被装饰者拥有相同的超类型,所以在任何需要原始对象的的场合,都可以用装饰过的对象代替

4. 装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,已达到特定的目的

5. 对象可以在任何时候被装饰,所以可以运行时动态地。不限量地用你喜欢的装饰者来装饰对象

定义装饰者模式

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

装饰者模式的类图

 

让星巴克咖啡也符合装饰者模式的类图

 

此处插入代码

 

package decorate;

public abstract class Beverage {
	public enum Size{TALL,GRANDE,VENTI};
	Size size=Size.TALL;
	String description="unkonow";
	public String getDiscription(){
		return description;
	}
	public void setSize(Size size){
		this.size=size;
	}
	public Size getSize(){
		return this.size;
	}
	public abstract double cost();
}

package decorate;
/*为了节约时间此处我只写了一种饮料类型*/
public class HouseBlend extends Beverage {
	//通过构造函数来传递参数
	public HouseBlend() {
		description="HouseBlend";
	}
	@Override
	public double cost() {
		return 0.89;
	}

}

package decorate;

public abstract class CondimentDecorator extends Beverage {
	public Beverage beverage;
	public abstract String getDiscription();
	public Size getSize(){
		return beverage.getSize();
	}
}


package decorate;

public class Milk extends CondimentDecorator {
	Beverage beverage;
	//为了把装饰者记录到实例变量中,通过把饮料当做构造器的参数,再由构造器将此饮料记录到实例变量中。
	public Milk(Beverage beverage) {
		this.beverage=beverage;
	}
	public String getDiscription(){
		return beverage.getDiscription()+",Milk";
	}
	@Override
	public double cost() {
		return beverage.cost()+0.20;
	}

}


package decorate;

public class Mocha extends CondimentDecorator{
	Beverage beverage;
	public Mocha(Beverage beverage) {
		this.beverage=beverage;
	}
	@Override
	public String getDiscription() {
		return beverage.getDiscription()+",Mocha";
	}

	@Override
	public double cost() {
		return beverage.cost()+0.20;
	}
	
}



package decorate;

public class Soy extends CondimentDecorator {
	Beverage beverage;
	public Soy(Beverage beverage) {
		this.beverage=beverage;
	}
	@Override
	public String getDiscription() {
		return beverage.getDiscription()+",Soy";
	}

	@Override
	public double cost() {
		double cost = beverage.cost();
		if (beverage.getSize() == Size.TALL) {
			cost += 0.10;
		} else if (beverage.getSize() == Size.GRANDE) {
			cost += 0.15;
		} else if (beverage.getSize() == Size.VENTI) {
			cost += 0.20;
		}
		return cost;
	}

}


package decorate;

public class Whip extends CondimentDecorator {
	Beverage beverage;
	public Whip(Beverage beverage) {
		this.beverage=beverage;
	}
	@Override
	public String getDiscription() {
		return beverage.getDiscription()+",Whip";
	}

	@Override
	public double cost() {
		return beverage.cost()+0.10;
	}

}



package decorate;

import decorate.Beverage.Size;

public class Test {
	public static void main(String[] args) {
		Beverage beverage=new HouseBlend();
		System.out.println(beverage.getDiscription()+"$"+beverage.cost());
		
		
		Beverage beverage2 = new HouseBlend();
		beverage2 = new Mocha(beverage2);
		beverage2 = new Mocha(beverage2);
		beverage2 = new Whip(beverage2);
		System.out.println(beverage2.getDiscription() 
				+ " $" + beverage2.cost());
		
		Beverage beverage3=new HouseBlend();
		beverage3.setSize(Size.VENTI);
		beverage3=new Soy(beverage3);
		beverage3=new Mocha(beverage3);
		beverage3=new Whip(beverage3);
		System.out.println(beverage3.getDiscription()+beverage3.cost());
	}
}


 

装饰者模式总结:

装饰者模式有能力为设计注入弹性,但也有“黑暗面”,有时候会再说设计中注入大量的小类,这偶尔导致别人不容易了解装饰者模式,有时候人们在客户代码中依赖某种特定类型,然后忽然导入装饰者,却又没有周详的考虑一切,不过通常可以透明的插入装饰者,客户程序不需要知道它在和装饰者打交道。还有就是,在采用装饰者实例化组件时,将增加代码的复杂度。一旦使用装饰者模式,不只需要实例化组件,还要把此组件包装进装饰者中。不过装饰者模式依然是一个很好的模式,适合用来建立有弹性的设计,维持开放-关闭原则。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值