class MP3Player{
private NormalBattery battery = new NormalBattery();
public void play(){
battery.usePower();
}
public int getBatteryPower(){
return battery.getPower();
}
public static void main(String... arg){
MP3Player player = new MP3Player();
/** 使用至沒電為止 */
while(player.getBatteryPower()>0){
player.play();
}
}
}
class NormalBattery{
private int power = 100; //預設電力100
public int getPower(){
return power;
}
public void usePower(){
power--; //每使用一次就遞減
}
}
Program A.為了不讓身為人類的你退化成猴子,我們還是將上面的程式修改一下,並加入一個Battery介面。
interface Battery{
int getPower();
void usePower();
}
class MP3Player{
private Battery battery;
public MP3Player(Battery battery){
this.battery = battery;
}
public static void main(String... arg){
/** 建構 player時將NormalBattery傳入當參數 */
MP3Player player = new MP3Player(new NormalBattery());
....
}
}
class NormalBattery implements Battery{
....
}
Program B.但是萬一MP3 Player用到一半,突然想把電池拆掉,又或者,一開始就不想要裝電池,該怎麼辦?如果是用建構子傳入參數的方式,因為沒有提供修改battery的方法,也強制MP3Player的使用者在建構MP3Player時就必須把battery的實體傳入。這種方式在某些情況下顯然不適用,因此我們改採另一種方法:不使用建構子傳參數,而是增加Setter方法。
class MP3Player{
private Battery battery;
public MP3Player(){}
public void setBattery(Battery battery){
this.battery = battery;
}
...
public static void main(String... arg){
MP3Player player = new MP3Player();
/** 設定電池 */
player.setBattery(new NormalBattery());
....
}
}
class NormalBattery implements Battery{
....
}
Program C.介紹到這裡,看似頗為人滿意,終於可以快樂大結局了。但是,在這個能源耗竭的時代,我們必須思考著如果有一天,MP3 Player的價錢會跟電池差不多,只更換電池就顯得沒有意義,連MP3 Player也必須要可以替換才行。為了因應這種變態的要求,MP3 Player廠商終於決定不再販賣MP3 Player,宣布轉型為MP3 Player出租商,改成以服務的方式收取費用。
為了因應石油不足對產業結構產生的衝擊,物件導向技術也有一套作法,讓你不需要去理會程式碼寫了什麼或怎麼使用,只要改一改訂單,MP3 Player和電池就送到府上供你使用。這種做法必須仰賴介面,將各個實作類別抽象化,因此必須新增 Player介面。
class NormalBattery implements Battery{....}
interface Battery{
....
}
interface Player{
void setBattery(Battery batery);
void play();
int getBatteryPower();
}
class MP3Player implements Player{
private Battery battery;
public MP3Player(){}
public void setBattery(Battery battery){....}
public void play(){....}
public int getBatteryPower(){....}
}
class NormalBattery implements Battery{....}
import java.io.*;Program D.
import java.util.*;
class Main{
public static void main(String... arg)throws Exception{
Properties props = new Properties();
/** 從config.txt檔案中讀出屬性 */
props.load(new FileInputStream("config.txt"));
/** 動態載入類別 */
Class playerClass =
Class.forName(props.getProperty("player"));
Class batteryClass =
Class.forName(props.getProperty("battery"));
Player player = (Player)playerClass.newInstance();
Battery battery = (Battery)batteryClass.newInstance();
/** 設定電池 */
player.setBattery(battery);
/** 使用至沒電為止 */
while(player.getBatteryPower()>0){
player.play();
}
}
}
config.txt→
player:MP3Player
battery:NormalBattery
一開始曾經提到,Martin Fowler曾經定義出三種DI的型態。 Program B.是屬於type 3,Constructor Injection; Program C.是type 2, Setter Injection; Program D.為type 1, Interface Injection。定義得那麼複雜,其實一點也不難。
沒有留言:
張貼留言