裝飾者模式,涉及的重要設計原則:類應該對擴充開放,對修改關閉。
裝飾者模式定義:
裝飾者模式動态地将責任附加到對象上。若要擴充功能,裝飾者提供了比繼承更有彈性的替代方案。
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;
}
/***
* 不僅顯示目前名,還說明被裝飾的名字
*/
@Override
public String getDescription() {
// TODO Auto-generated method stub
return beverage.getDescription() + ", Milk";
}
/***
* 擷取本身的價格和咖啡的價格
*/
@Override
public double cost() {
// TODO Auto-generated method stub
double 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;
}
/***
* 不僅顯示目前名,還說明被裝飾的名字
*/
@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();
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;
}
/***
* 不僅顯示目前名,還說明被裝飾的名字
*/
@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();
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;
}
/***
* 不僅顯示目前名,還說明被裝飾的名字
*/
@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();
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();
}
/***
* 不僅顯示目前名,還說明被裝飾的名字
*/
@Override
public String getDescription() {
// TODO Auto-generated method stub
return beverage.getDescription() + ", Milk";
}
/***
* 擷取本身的價格和咖啡的價格
*/
@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.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();
}
/***
* 不僅顯示目前名,還說明被裝飾的名字
*/
@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.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();
}
/***
* 不僅顯示目前名,還說明被裝飾的名字
*/
@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.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();
}
/***
* 不僅顯示目前名,還說明被裝飾的名字
*/
@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.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