一、装饰者模式
动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
简单的来说就是AB两个类都继承了C抽象类,B也是抽象类也是装饰类,A是主题类专门被装饰,然后又有一堆继承了B装饰类的实现类比如(Z、X、D),装饰类通过以C c为属性,通过构造函数来实例化C c。从而达到装饰的目的。
本例子以卖咖啡为例子,主题就是咖啡类型,装饰者就是配料。
二、设计原则
类应该对外扩展开放,对内修改关闭。
对外:就是装饰类Z、X、D、以C为属性
对内:就是自身方法属性不受外界影响
三、代码实现
1、抽象类
package com.oyhp.component;
public abstract class Beverage {
//杯子容量大小类型
public final static int TALL=0;
public final static int GRANDE=1;
public final static int VENTI=2;
//杯子容量大小
private int size;
String description = "Unkown Beverage";
public String getDescription(){
return description;
}
public abstract double cost();
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
}
2、主题类(被装饰者)
package com.oyhp.component;
//浓缩咖啡
public class Espresso extends Beverage{
public Espresso(){
description = "Espresso";
}
@Override
public double cost() {
// TODO Auto-generated method stub
return 1.99;
}
}
package com.oyhp.component;
//综合咖啡
public class HouseBlend extends Beverage{
public HouseBlend() {
// TODO Auto-generated constructor stub
description = "HouseBlend";
}
@Override
public double cost() {
// TODO Auto-generated method stub
return 0.89;
}
}
3、装饰者
package com.oyhp.decorator;
import com.oyhp.component.Beverage;
public abstract class CondimentDecorator extends Beverage{
public abstract String getDescription();
}
package com.oyhp.decorator;
import com.oyhp.component.Beverage;
//装饰者-摩卡配料
public class Mocha extends CondimentDecorator{
//使用了组合,针对接口少用实现的原则,把咖啡类型当成属性
Beverage beverage;
/**
* 这里的做法是:把咖啡类型当作构造器的参数,再由构造器将此咖啡类型记录在实例变量(即属性)中。
* */
public Mocha(Beverage beverage) {
// TODO Auto-generated constructor stub
this.beverage = beverage;
}
public Mocha(Beverage beverage,int size) {
// TODO Auto-generated constructor stub
this.beverage = beverage;
setSize(size);
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return beverage.getDescription() + ", Mocha";
}
@Override
public double cost() {
// TODO Auto-generated method stub
double cost = beverage.cost();
if(getSize() == Beverage.TALL){
cost += 0.1;
}else if(getSize() == Beverage.GRANDE){
cost += 0.25;
}else if(getSize() == Beverage.VENTI){
cost += 0.30;
}
return cost;
}
}
package com.oyhp.decorator;
//豆浆配料
import com.oyhp.component.Beverage;
public class Soy extends CondimentDecorator{
Beverage beverage;
public Soy(Beverage beverage) {
// TODO Auto-generated constructor stub
this.beverage = beverage;
}
public Soy(Beverage beverage,int size) {
// TODO Auto-generated constructor stub
this.beverage = beverage;
setSize(size);
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return beverage.getDescription() + ", Soy";
}
@Override
public double cost() {
// TODO Auto-generated method stub
double cost = beverage.cost();
if(getSize() == Beverage.TALL){
cost += 0.1;
}else if(getSize() == Beverage.GRANDE){
cost += 0.15;
}else if(getSize() == Beverage.VENTI){
cost += 0.20;
}
return cost;
}
}
package com.oyhp.decorator;
import com.oyhp.component.Beverage;
//奶泡配料
public class Whip extends CondimentDecorator{
Beverage beverage;
public Whip(Beverage beverage) {
// TODO Auto-generated constructor stub
this.beverage = beverage;
}
public Whip(Beverage beverage,int size) {
// TODO Auto-generated constructor stub
this.beverage = beverage;
setSize(size);
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return beverage.getDescription() + ", Whip";
}
@Override
public double cost() {
// TODO Auto-generated method stub
double cost = beverage.cost();
if(getSize() == Beverage.TALL){
cost += 0.3;
}else if(getSize() == Beverage.GRANDE){
cost += 0.45;
}else if(getSize() == Beverage.VENTI){
cost += 0.50;
}
return cost;
}
}
4、main
package com.oyhp.main;
import com.oyhp.component.Beverage;
import com.oyhp.component.Espresso;
import com.oyhp.decorator.Mocha;
import com.oyhp.decorator.Soy;
import com.oyhp.decorator.Whip;
public class DoRun {
public static void main(String[] args) {
Beverage espresso = new Espresso();
System.out.println(espresso.getDescription() + " $" + espresso.cost());
/**装饰者的精华之处,让被装饰者(咖啡类型)和装饰者(CondimentDecorator)都继承了Beverage元件
* 大家都是同一个超类的,类型可以相互转换;
* 装饰者通过构造器把被装饰者(咖啡类型)当成参数,把它包起来。*/
espresso = new Mocha(espresso,Beverage.VENTI);
espresso = new Soy(espresso,Beverage.VENTI);
espresso = new Whip(espresso,Beverage.VENTI);
System.out.println(espresso.getDescription() + " $" + espresso.cost());
}
}
四、装饰者大局观
五、总结
1、封装变化 2、多用组合、少用继承 3、针对接口编程、不针对实现编程 4、为交互对象之间的松耦合设计而努力
5、对扩展开放、对修改关闭