本文講闡述自己對裝飾者模式的理解,以及在項目中的應用,書寫的思路圍繞着以下幾個問題一步步開展,希望對大家能有點幫助。
問題思路:
1.什麼是裝飾者模式,官方定義&自己的理解;
2.爲什麼會有這樣的需求(是爲了解決什麼問題),典型的例子;
3.裝飾者模式的優點;
4.裝飾者模式在Android中的應用;
5.剖析在Android中應用的源碼,看看官方的規範並提示自己在使用時要注意的點。
1.什麼是裝飾者模式?
簡單的一句話:動態地給一個對象添加一些額外的職責;我認爲這是對裝飾者模式最好的解釋。
關鍵字:動態地、對象、添加、額外的職責。
2.爲什麼會有這樣的需求,舉兩個典型的例子;
比如:
①假設設計遊戲的時候不同的人形,有的是A對象+白褲子+紅襯衫;B對象+白褲子+白襯衫;A對象+白褲子+白襯衫等等有很多的人形,這個時候你要是每一個對象都寫死屬性,比如這樣:
class A {
public String getDescription() {
String description = "白褲子+白襯衫";
return description;
}
}
抽象一個父類,然後需要不同屬性的的子類去實現父類,這樣的去實現的話,會有太多的子類,這種現象叫做類爆炸。
通常可以使用繼承來是實現功能的擴展,如果這些需要擴展的功能種類很繁多,那麼必然會生成很多子類,增加系統的複雜性,這種現象叫類爆炸。”
②典型的還有星巴克咖啡點餐管理例子,不同的咖啡+不同的配料,管理計算各種飲料的價格,怎麼去實現。這是典型裝飾者的使用。
具體的代碼是這樣去實現的:
被裝飾者:
/**
* 咖啡父類
*/
public abstract class Coffee {
public String description = "";
/**
* getCost()方法是抽象的,必須要子類自己去實現
*/
public abstract double getCost();
public String getDescription() {
return description;
}
}
子類類型:
/**
* 深培咖啡
*/
public class DarkRoastCoffee extends Coffee {
public DarkRoastCoffee() {
description = "深培咖啡";
}
@Override
public double getCost() {
return 10;
}
}
/**
* 濃縮咖啡
*/
public class EspressoCoffee extends Coffee {
public EspressoCoffee() {
description = "濃縮咖啡";
}
@Override
public double getCost() {
return 8.8;
}
}
裝飾者(配料):
/**
* 調料父類
* 繼承Coffee,是爲了擁有公有的超類,這裏的繼承是爲了繼承類型,而不是行爲
*/
public abstract class Condiment extends Coffee {
@Override
public abstract String getDescription();
}
這裏的配料繼承的是Coffee,主要是爲了有共同的超類。
在子類去繼承Codiment的時候必然要重寫Condiment中定義的抽象方法和Coffee中定義的抽象方法。
/**
* 配料牛奶
*/
public class MilkCondiment extends Condiment {
private final Coffee coffee;
public double milkPrice = 2.1;
public MilkCondiment(Coffee coffee) {
this.coffee = coffee;
}
@Override
public double getCost() {
return milkPrice + coffee.getCost();
}
@Override
public String getDescription() {
return coffee.getDescription() + ",加牛奶";
}
}
/**
* 摩卡對象是一個裝飾者
*/
public class MochaCondiment extends Condiment {
private final Coffee coffee;
public double mochaPrice = 5.2;
public MochaCondiment(Coffee coffee) {
this.coffee = coffee;
}
@Override
public double getCost() {
return mochaPrice+coffee.getCost();
}
@Override
public String getDescription() {
return coffee.getDescription()+",加摩卡";
}
}
奶泡:
/**
* 奶泡配料
*/
public class WhipCondiment extends Condiment {
private final Coffee coffee;
private double whipPrice = 3.0;
public WhipCondiment(Coffee coffee) {
this.coffee = coffee;
}
@Override
public double getCost() {
return whipPrice+coffee.getCost();
}
@Override
public String getDescription() {
return coffee.getDescription()+"加奶泡";
}
}
使用的時候:
public class Test1Coffee {
public static void main(String[] args) {
Coffee mochaCondiment = new MochaCondiment(new MilkCondiment(new DarkRoastCoffee()));
System.out.println("我曹++"+mochaCondiment.getDescription()+";價格是"+mochaCondiment.getCost());
Coffee mochaCondiment1 = new MochaCondiment(new MochaCondiment(new DarkRoastCoffee()));
System.out.println("我曹1++"+mochaCondiment1.getDescription()+";價格是"+mochaCondiment1.getCost());
Coffee whipCondiment = new WhipCondiment(new MochaCondiment(new EspressoCoffee()));
System.out.println("我曹2++"+whipCondiment.getDescription()+";價格是"+whipCondiment.getCost());
}
}
輸出結果:
“我曹++深培咖啡,加牛奶,加摩卡;價格是17.3
我曹1++深培咖啡,加摩卡,加摩卡;價格是20.4
我曹2++濃縮咖啡,加摩卡加奶泡;價格是17.0”
哇塞,多麼有意思的代碼啊。作爲一個非科班出身的程序員,感覺看到這種的代碼有種莫名的興奮啊。
Coffee whipCondiment = new WhipCondiment(new MochaCondiment(new EspressoCoffee()));
說到這裏解釋這個例子的專用的UML圖如下,大家一看就會明白很多:
圖一:星巴克咖啡點餐管理圖示:
圖二:顧客點了一杯加奶泡加摩卡的深培咖啡圖示:
星巴克咖啡點餐系統基本原理就是這樣。
3.其實在Android中比較典型的應用就是JAVA中IO流:
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("..")));
這是典型的裝飾者模式。
4.還有一個就是ListView組件addHeaderView()方法的源碼,就比較明顯的使用的是裝飾者模式,具體的源碼分析再接下來會分析。