Java设计模式:装饰者模式(Decorator Pattern)

来源:互联网 发布:制作新闻的软件 编辑:程序博客网 时间:2024/05/22 00:46

装饰者模式,涉及的重要设计原则:类应该对扩展开放,对修改关闭

装饰者模式定义:

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

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.0DarkRoast, Mocha, Mocha, Whip: $ 10.3HouseBlend, 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

阅读全文
1 0
原创粉丝点击