Head First 設計模式--裝飾者模式
阿新 • • 發佈:2019-01-31
星巴茲咖啡準備更新訂單系統,為的是不違背開放-關閉的設計原則:類應該對擴充套件開放,對修改關閉。
我們的目標是允許類容易擴充套件,在不修改現有程式碼的情況下,就可搭配新的行為。
這個目標需要使用裝飾者模式實現:以飲料為主體,然後執行調料來“裝飾”飲料。
1.定義裝飾者模式:裝飾者模式動態的將責任附加到物件上,若要擴充套件功能,裝飾者提供了比繼承更具有彈性的替代方案。
裝飾者模式類圖:
2.把星巴茲咖啡系統進行修改,使其符合裝飾者類圖:
3.具體實現:
從飲料下手,將飲料作為一個抽象類:
調料抽象類,也就是裝飾者類:package com.wk.cafe; public abstract class Beverage { String description = "Unkown Beverage"; public String getDescription(){ return description; } public abstract double cost(); }
package com.wk.cafe;
public abstract class CondimentDecorator extends Beverage{
public abstract String getDescription();
}
實現具體的飲料:
package com.wk.cafe; public class Espresso extends Beverage { public Espresso(){ description = "Espresso"; } public double cost(){ return 1.99; } }
package com.wk.cafe;
public class HouseBlend extends Beverage {
public HouseBlend() {
description = "HouseBlend";
}
public double cost() {
return 0.89;
}
}
實現具體裝飾者類:
package com.wk.cafe; public class Soy extends CondimentDecorator { Beverage beverage; public Soy(Beverage beverage){ this.beverage = beverage; } public String getDescription(){ return beverage.getDescription()+",Soy"; } public double cost(){ return 0.20+beverage.cost(); } }
package com.wk.cafe;
public class Whip extends CondimentDecorator {
Beverage beverage;
public Whip(Beverage beverage){
this.beverage = beverage;
}
public String getDescription(){
return beverage.getDescription()+",Whip";
}
public double cost(){
return 0.20+beverage.cost();
}
}
package com.wk.cafe;
public class Mocha extends CondimentDecorator {
Beverage beverage;
public Mocha(Beverage beverage){
this.beverage = beverage;
}
public String getDescription(){
return beverage.getDescription()+",Mocha";
}
public double cost(){
return 0.20+beverage.cost();
}
}
測試程式碼:
package com.wk.cafe;
public class StartbuzzCoffee {
public static void main(String args[]) {
Beverage beverage1 = new Espresso();
System.out.println(beverage1.getDescription() + " $"
+ beverage1.cost());
beverage1 = new Mocha(beverage1);
beverage1 = new Whip(beverage1);
System.out.println(beverage1.getDescription() + " $"
+ beverage1.cost());
Beverage beverage2 = new HouseBlend();
beverage2 = new Soy(beverage2);
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);
System.out.println(beverage2.getDescription() + " $"
+ beverage2.cost());
}
}
測試結果:
JAVA中的裝飾者模式(java.io類):
Java I/O引出裝飾者模式的一個“缺點”:利用裝飾者模式,會造成設計中存在大量的小類。
我們可以編寫自己的Java I/O裝飾者(即ConcreteDecorator),它的作用是把輸入流中的所有小寫字母轉成大寫:
程式碼如下:
package com.wk.cafe;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
public class UpperCaseInputStream extends FilterInputStream {
protected UpperCaseInputStream(InputStream in) {
super(in);
// TODO Auto-generated constructor stub
}
public int read() throws IOException {
int c = super.read();
return (c == -1 ? c : Character.toUpperCase((char) c));
}
public int read(byte[] b, int offset, int len) throws IOException {
int result = super.read(b, offset, len);
for (int i = offset; i < offset + result; i++) {
b[i] = (byte) Character.toUpperCase((char) b[i]);
}
return result;
}
}
對剛剛寫好的I/O裝飾者進行測試:
package com.wk.cafe;
import java.io.*;
public class UpperCaseInputStreamTest {
public static void main(String[] args) throws IOException {
int c;
try {
InputStream in = new UpperCaseInputStream(new BufferedInputStream(
new FileInputStream("E:\\inputtest.txt")));
while ((c = in.read()) >= 0) {
System.out.print((char) c);
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}