模式:装饰者模式(Decorator Pattern)"/>
Java设计模式:装饰者模式(Decorator Pattern)
装饰者模式,涉及的重要设计原则:类应该对扩展开放,对修改关闭。
装饰者模式定义:
装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
UML类图:
装饰者模式事例:
咖啡店
咖啡种类:
1)深焙咖啡(DarkRoast)
2)家庭混合咖啡(HouseBlend)
3)浓咖啡(Espresso)
4)低咖啡因咖啡(Decaf)
5)其它咖啡。。。
咖啡调料:
1)摩卡(Mocha)
2)牛奶(Milk)
3)豆浆(Soy)
4)奶泡(Whip)
5)其它调料。。。
点单:
要一份加了摩卡和奶泡的深焙咖啡...等等
UML类图
代码实现:
Beverage.java
package com.jing.decorator;/*** 所有饮料的抽象超类* @author LiuJing**/
public abstract class Beverage {/*** 饮料的名字*/String description = "Unknow Beverage";/** 获取饮料的名字*/public String getDescription(){return description;}/**** 获取饮料的价格* @return 返回计算后的总价*/public abstract double cost();}
DarkRoast.java
package com.jing.decorator;import java.text.DecimalFormat;/**** 深烤咖啡* @author LiuJing**/
public class DarkRoast extends Beverage {/**** 构造时确定名字*/public DarkRoast(){description = "DarkRoast";}/**** 价格*/public double cost() {double cost = 10.0;// 用于保存2位小数DecimalFormat df = new DecimalFormat("#.00");return Double.valueOf(df.format(cost));}
}
Decaf.java
package com.jing.decorator;import java.text.DecimalFormat;/**** 低咖啡因咖啡* @author LiuJing**/
public class Decaf extends Beverage {/**** 构造时确定名字*/public Decaf() {description = "Decaf";}/**** 价格*/public double cost() {double cost = 11.0;DecimalFormat df = new DecimalFormat("#.00");return Double.valueOf(df.format(cost));}
}
Espresso.java
package com.jing.decorator;import java.text.DecimalFormat;/**** 浓咖啡* @author LiuJing**/
public class Espresso extends Beverage {/**** 构造时确定其名字*/public Espresso(){description = "Espresso";}/**** 方法返回 该饮料的价格*/public double cost() {double cost = 12.0;DecimalFormat df = new DecimalFormat("#.00");return Double.valueOf(df.format(cost));}
}
HouseBlend.java
package com.jing.decorator;import java.text.DecimalFormat;/**** 家庭混合咖啡* @author LiuJing**/
public class HouseBlend extends Beverage {/**** 构造时确定其名字*/public HouseBlend(){description = "HouseBlend";}/**** 返回该咖啡的价格*/public double cost() {double cost = 13.0;DecimalFormat df = new DecimalFormat("#.00");return Double.valueOf(df.format(cost));}}
CondimentDecorator.java
package com.jing.decorator;/**** 调料装饰者抽象超类,继承至 Beverage,便于类型的统一,能彼此替换。* @author LiuJing**/
public abstract class CondimentDecorator extends Beverage {/**** 用于保存要装饰的咖啡对象*/Beverage beverage;/**** 所有子类都必须重新实现 getDescription()方法*/public abstract String getDescription();}
Milk.java
package com.jing.decorator;import java.text.DecimalFormat;/**** 咖啡调料 牛奶 Milk >> CondimentDecorator >> Beverage* @author LiuJing**/
public class Milk extends CondimentDecorator {/*** 构造时确定要加给谁* @param beverage*/public Milk(Beverage beverage){this.beverage = beverage;}/**** 不仅显示当前名,还说明被装饰的名字 */@Overridepublic String getDescription() {// TODO Auto-generated method stubreturn beverage.getDescription() + ", Milk";}/**** 获取本身的价格和咖啡的价格*/@Overridepublic double cost() {// TODO Auto-generated method stubdouble cost = beverage.cost();cost += 0.1;DecimalFormat df = new DecimalFormat("#.00");return Double.valueOf(df.format(cost));}}
Mocha.java
package com.jing.decorator;import java.text.DecimalFormat;/**** 咖啡调料 摩卡 Mocha >> CondimentDecorator >> Beverage* * @author LiuJing* */
public class Mocha extends CondimentDecorator {/*** 构造时确定要加给谁* * @param beverage*/public Mocha(Beverage beverage) {this.beverage = beverage;}/**** 不仅显示当前名,还说明被装饰的名字*/@Overridepublic String getDescription() {// TODO Auto-generated method stubreturn beverage.getDescription() + ", Mocha";}/**** 获取本身的价格和咖啡的价格*/@Overridepublic double cost() {// TODO Auto-generated method stubdouble cost = beverage.cost();cost += 0.1;DecimalFormat df = new DecimalFormat("#.00");return Double.valueOf(df.format(cost));}}
Soy.java
package com.jing.decorator;import java.text.DecimalFormat;/**** 咖啡调料 豆浆 Soy >> CondimentDecorator >> Beverage* * @author LiuJing* */
public class Soy extends CondimentDecorator {/*** 构造时确定要加给谁* * @param beverage*/public Soy(Beverage beverage) {this.beverage = beverage;}/**** 不仅显示当前名,还说明被装饰的名字*/@Overridepublic String getDescription() {// TODO Auto-generated method stubreturn beverage.getDescription() + ", Soy";}/**** 获取本身的价格和咖啡的价格*/@Overridepublic double cost() {// TODO Auto-generated method stubdouble cost = beverage.cost();cost += 0.1;DecimalFormat df = new DecimalFormat("#.00");return Double.valueOf(df.format(cost));}}
Whip.java
package com.jing.decorator;import java.text.DecimalFormat;/**** 咖啡调料 奶泡 Whip >> CondimentDecorator >> Beverage* * @author LiuJing* */
public class Whip extends CondimentDecorator {/*** 构造时确定要加给谁* * @param beverage*/public Whip(Beverage beverage) {this.beverage = beverage;}/**** 不仅显示当前名,还说明被装饰的名字*/@Overridepublic String getDescription() {// TODO Auto-generated method stubreturn beverage.getDescription() + ", Whip";}/**** 获取本身的价格和咖啡的价格*/@Overridepublic double cost() {// TODO Auto-generated method stubdouble cost = beverage.cost();cost += 0.1;DecimalFormat df = new DecimalFormat("#.00");return Double.valueOf(df.format(cost));}}
测试类
Test.java
package com.jing.decorator;public class Test {/*** @param args*/public static void main(String[] args) {// TODO Auto-generated method stub// 点了一份浓咖啡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(beverage3); // 加 豆浆装饰beverage3 = new Mocha(beverage3); // 再加 摩卡装饰beverage3 = new Whip(beverage3); // 再加 奶泡装饰System.out.println(beverage3.getDescription() + ": $ " + beverage3.cost());// 用 工厂模式 和 生成器模式,可以更好的建立被 装饰者对象}}
输出:
Espresso: $ 12.0
DarkRoast, Mocha, Mocha, Whip: $ 10.3
HouseBlend, Soy, Mocha, Whip: $ 13.3
扩展:
现在咖啡要有区分 大,中,小杯的价格;
同理,
调料因为杯的大小也要区分不同的价格;
Beverage.java
package com.jing.decorator.size;/*** 所有饮料的抽象超类* @author LiuJing**/
public abstract class Beverage {/*** 杯子的容量类型*/public final static int TALL = 1;public final static int GRANDE = 2;public final static int VENTI = 3;/*** 杯子的容量*/private int volume = 2; // 默认为中杯public int getSize() {return volume;}public void setSize(int valume) {this.volume = valume;}public String getSizeDescription() {String type = "未知杯的大小 ";switch(volume){case TALL:type = "小杯";break;case GRANDE:type = "中杯";break;case VENTI:type = "大杯";break;}return type;}/*** 饮料的名字*/String description = "Unknow Beverage";/** 获取饮料的名字*/public String getDescription(){return description;}/**** 获取饮料的价格* @return 返回计算后的总价*/public abstract double cost();}
DarkRoast.java
package com.jing.decorator.size;import java.text.DecimalFormat;/**** 深烤咖啡* @author LiuJing**/
public class DarkRoast extends Beverage {/**** 构造时确定名字*/public DarkRoast(){description = "DarkRoast";}public DarkRoast(int volume){setSize(volume);description = "DarkRoast";}/**** 价格*/public double cost() {double cost = 0.0;if (getSize() == Beverage.TALL) {cost = 10.0;}else if (getSize() == Beverage.GRANDE){cost = 15.0;}else if (getSize() == Beverage.VENTI){cost = 20.0;}DecimalFormat df = new DecimalFormat("#.00");return Double.valueOf(df.format(cost));}}
Decaf.java
package com.jing.decorator.size;import java.text.DecimalFormat;/**** 低咖啡因咖啡* @author LiuJing**/
public class Decaf extends Beverage {/**** 构造时确定名字*/public Decaf() {description = "Decaf";}public Decaf(int volume){setSize(volume);description = "Decaf";}/**** 价格*/public double cost() {double cost = 0.0;if (getSize() == Beverage.TALL) {cost = 11.0;}else if (getSize() == Beverage.GRANDE){cost = 16.0;}else if (getSize() == Beverage.VENTI){cost = 21.0;}DecimalFormat df = new DecimalFormat("#.00");return Double.valueOf(df.format(cost));}}
Espresso.java
package com.jing.decorator.size;import java.text.DecimalFormat;/**** 浓咖啡* @author LiuJing**/
public class Espresso extends Beverage {/**** 构造时确定其名字*/public Espresso(){description = "Espresso";}public Espresso(int volume){setSize(volume);description = "Espresso";}/**** 方法返回 该饮料的价格*/public double cost() {double cost = 0.0;if (getSize() == Beverage.TALL) {cost = 12.0;}else if (getSize() == Beverage.GRANDE){cost = 17.0;}else if (getSize() == Beverage.VENTI){cost = 22.0;}DecimalFormat df = new DecimalFormat("#.00");return Double.valueOf(df.format(cost));}
}
HouseBlend.java
package com.jing.decorator.size;import java.text.DecimalFormat;/**** 家庭混合咖啡* @author LiuJing**/
public class HouseBlend extends Beverage {/**** 构造时确定其名字*/public HouseBlend(){description = "HouseBlend";}public HouseBlend(int volume){setSize(volume);description = "HouseBlend";}/**** 返回该咖啡的价格*/public double cost() {double cost = 0.0;if (getSize() == Beverage.TALL) {cost = 13.0;}else if (getSize() == Beverage.GRANDE){cost = 18.0;}else if (getSize() == Beverage.VENTI){cost = 23.0;}DecimalFormat df = new DecimalFormat("#.00");return Double.valueOf(df.format(cost));}}
CondimentDecorator.java
package com.jing.decorator.size;/**** 调料装饰者抽象超类,继承至 Beverage,便于类型的统一,能彼此替换。* @author LiuJing**/
public abstract class CondimentDecorator extends Beverage {/**** 要装饰的咖啡对象*/Beverage beverage;/**** 所有子类都必须重新实现 getDescription()方法*/public abstract String getDescription();}
Milk.java
package com.jing.decorator.size;import java.text.DecimalFormat;/**** 咖啡调料 牛奶 Milk >> CondimentDecorator >> Beverage* @author LiuJing**/
public class Milk extends CondimentDecorator {/*** 构造时确定要加给谁* @param beverage*/public Milk(Beverage beverage){this.beverage = beverage;setSize(beverage.getSize());}public int getSize(){return beverage.getSize();}/**** 不仅显示当前名,还说明被装饰的名字 */@Overridepublic String getDescription() {// TODO Auto-generated method stubreturn beverage.getDescription() + ", Milk";}/**** 获取本身的价格和咖啡的价格*/@Overridepublic double cost() {// TODO Auto-generated method stubdouble cost = beverage.cost();if (getSize() == Beverage.TALL){cost += 0.1;} else if (getSize() == Beverage.GRANDE){cost += 0.2;} else if (getSize() == Beverage.VENTI){cost += 0.3;}DecimalFormat df = new DecimalFormat("#.00");return Double.valueOf(df.format(cost));}}
Mocha.java
package com.jing.decorator.size;import java.text.DecimalFormat;/**** 咖啡调料 摩卡 Mocha >> CondimentDecorator >> Beverage* @author LiuJing**/
public class Mocha extends CondimentDecorator {/*** 构造时确定要加给谁* @param beverage*/public Mocha(Beverage beverage){this.beverage = beverage;setSize(beverage.getSize());}public int getSize(){return beverage.getSize();}/**** 不仅显示当前名,还说明被装饰的名字 */@Overridepublic String getDescription() {// TODO Auto-generated method stubreturn beverage.getDescription() + ", Mocha";}/**** 获取本身的价格和咖啡的价格*/@Overridepublic double cost() {// TODO Auto-generated method stubdouble cost = beverage.cost();if (getSize() == Beverage.TALL){cost += 0.1;} else if (getSize() == Beverage.GRANDE){cost += 0.2;} else if (getSize() == Beverage.VENTI){cost += 0.3;}DecimalFormat df = new DecimalFormat("#.00");return Double.valueOf(df.format(cost));}}
Soy.java
package com.jing.decorator.size;import java.text.DecimalFormat;/**** 咖啡调料 豆浆 Soy >> CondimentDecorator >> Beverage* @author LiuJing**/
public class Soy extends CondimentDecorator {/*** 构造时确定要加给谁* @param beverage*/public Soy(Beverage beverage){this.beverage = beverage;setSize(beverage.getSize());}public int getSize(){return beverage.getSize();}/**** 不仅显示当前名,还说明被装饰的名字 */@Overridepublic String getDescription() {// TODO Auto-generated method stubreturn beverage.getDescription() + ", Soy";}/**** 获取本身的价格和咖啡的价格*/@Overridepublic double cost() {// TODO Auto-generated method stubdouble cost = beverage.cost();if (getSize() == Beverage.TALL){cost += 0.1;} else if (getSize() == Beverage.GRANDE){cost += 0.2;} else if (getSize() == Beverage.VENTI){cost += 0.3;}DecimalFormat df = new DecimalFormat("#.00");return Double.valueOf(df.format(cost));}}
Whip.java
package com.jing.decorator.size;import java.text.DecimalFormat;/**** 咖啡调料 奶泡 Whip >> CondimentDecorator >> Beverage* @author LiuJing**/
public class Whip extends CondimentDecorator {/*** 构造时确定要加给谁* @param beverage*/public Whip(Beverage beverage){this.beverage = beverage;setSize(beverage.getSize());}public int getSize(){return beverage.getSize();}/**** 不仅显示当前名,还说明被装饰的名字 */@Overridepublic String getDescription() {// TODO Auto-generated method stubreturn beverage.getDescription() + ", Whip";}/**** 获取本身的价格和咖啡的价格*/@Overridepublic double cost() {// TODO Auto-generated method stubdouble cost = beverage.cost();if (getSize() == Beverage.TALL){cost += 0.1;} else if (getSize() == Beverage.GRANDE){cost += 0.2;} else if (getSize() == Beverage.VENTI){cost += 0.3;}DecimalFormat df = new DecimalFormat("#.00");return Double.valueOf(df.format(cost));}}
Test.java
package com.jing.decorator.size;public class Test {/*** @param args*/public static void main(String[] args) {// TODO Auto-generated method stub// 点了一份浓咖啡Beverage beverage = new Espresso(); // 使用默认中杯System.out.println(beverage.getSizeDescription()+ beverage.getDescription() + ": $ " + beverage.cost());// 点了一份深烤Beverage beverage2 = new DarkRoast();// 默认为中号beverage2.setSize(Beverage.TALL); // 重新设置杯号为小号beverage2 = new Mocha(beverage2); // 加 摩卡装饰beverage2 = new Mocha(beverage2); // 再加 摩卡装饰beverage2 = new Whip(beverage2); // 再加 奶泡装饰System.out.println(beverage2.getSizeDescription()+ beverage2.getDescription() + ": $ " + beverage2.cost());// 点了一份家庭混合Beverage beverage3 = new HouseBlend(Beverage.VENTI); // 构造初始时就设为大号beverage3 = new Soy(beverage3); // 加 豆浆装饰beverage3 = new Mocha(beverage3); // 再加 摩卡装饰beverage3 = new Whip(beverage3); // 再加 奶泡装饰System.out.println(beverage3.getSizeDescription()+ beverage3.getDescription()+ ": $ " + beverage3.cost());// 用 工厂模式 和 生成器模式,可以更好的建立被 装饰者对象}}
输出:
中杯Espresso: $ 17.0
小杯DarkRoast, Mocha, Mocha, Whip: $ 10.3
大杯HouseBlend, Soy, Mocha, Whip: $ 23.9
更多推荐
Java设计模式:装饰者模式(Decorator Pattern)
发布评论