2013-08-25 35 views
12

在工廠模式中使用反射是否是一種很好的做法?在工廠模式中使用反射

public class MyObjectFactory{ 
private Party party; 

public Party getObject(String fullyqualifiedPath) 
{ 
    Class c = Class.forName(fullyqualifiedPath); 
    party = (PersonalParty)c.newInstance(); 
    return party; 
} 
} 

PersonalParty實現黨

+1

這是否有任何嚴重的用例。一般來說,我會考慮反思作爲我的最後手段。特別是爲了這個目的。 –

+0

JSf2.0這樣的框架如何使用註釋?它們應該使用Reflection API在運行時實例化對象? – Ullas

+1

如果是關於JSF,那麼請標籤是這樣的。 –

回答

9

工廠模式的目的是去耦合一些代碼從它消耗對象的運行時類型:

// This code doesn't need to know that the factory is returning 
// an object of type `com.example.parties.SurpriseParty` 
AbstractParty myParty = new PartyFactory().create(...); 

使用這樣的代碼,該PartyFactory專門負責確定或知道應使用哪種運行時類型。

通過傳入您需要的班級的完全限定名稱,您可以放棄這種優點。這是怎麼回事...

// This code obviously DOES know that the factory is returning 
// an object of type `com.example.parties.SurpriseParty`. 
// Now only the compiler doesn't know or enforce that relationship. 
AbstractParty myParty = new PartyFactory().create("com.example.parties.SurpriseParty"); 

...從簡單的聲明myPartycom.example.parties.SurpriseParty類型的有什麼不同?最後你的代碼也是一樣,但你已經放棄了靜態類型驗證。這意味着您在投入獲得強大類型的Java的某些好處的同時不會產生任何好處。如果你刪除了com.example.parties.SurpriseParty你的代碼仍然會編譯,你的IDE將不會給你任何錯誤信息,並且直到運行時你都不會意識到這個代碼和com.example.parties.SurpriseParty之間有關係 - 這很糟糕。

最起碼,我建議你至少改變這種代碼,所以這個方法的參數是一個簡單的類名稱,而不是一個完全合格的名稱:

// I took the liberty of renaming this class and it's only method 
public class MyPartyFactory{ 

    public Party create(String name) 
    { 
     //TODO: sanitize `name` - check it contains no `.` characters 
     Class c = Class.forName("com.example.parties."+name); 
     // I'm going to take for granted that I don't have to explain how or why `party` shouldn't be an instance variable. 
     Party party = (PersonalParty)c.newInstance(); 
     return party; 
    } 
} 

下一頁:這是不好的做法,使用Class.forName(...)?這取決於替代方案以及這些String參數(name)與該工廠將提供的類之間的關係。如果替代是一個大的條件:

if("SurpriseParty".equals(name) { 
    return new com.example.parties.SurpriseParty(); 
} 
else if("GoodbyeParty".equals(name)) { 
    return new com.example.parties.GoodbyeParty(); 
} 
else if("PartyOfFive".equals(name)) { 
    return new com.example.parties.PartyOfFive(); 
} 
else if(/* ... */) { 
    // ... 
} 
// etc, etc etc 

...這是不可擴展的。由於該工廠創建的運行時類型的名稱與name參數的值之間存在明顯的可觀察關係,因此應該考慮使用Class.forName代替。這樣,每次向系統添加新的Party類型時,您的Factory對象都不需要更改代碼。


你可以考慮的其他東西是使用AbstractFactory模式。如果你的消費代碼如下所示:

AbstractParty sParty = new PartyFactory().create("SurpriseParty"); 
AbstractParty gbParty = new PartyFactory().create("GoodByeParty"); 

...那裏經常發生的被請求方類型的數量有限,您應該考慮爲這些不同類型的政黨不同的方法:

public class PartyFactory { 

    public Party getSurpriseParty() { ... } 
    public Party getGoodByeParty() { ... } 

} 

...這將允許您利用Java的靜態類型。

該解決方案確實,但是,意味着每次添加一個新的類型的Party你必須改變工廠對象 - 所以無論反射溶液或AbstractFactory是一個更好的解決方案實際上取決於多久,以及如何快速您將會添加Party類型。每天都有新類型?使用反射。每十年一個新派對類型?使用AbstractFactory

+0

感謝您的詳細解釋Sir .. – Ullas

+0

@烏拉斯 - 我的榮幸。增加了一個段落,強調何時應該使用反射解決方案,而不是何時應該使用'AsbtractFactory'。 –

1

使用反射這種方式(以Class.forName)幾乎總是不好的應用程序設計的標誌。有一些類型,如果你正在做某種外部庫或插件的動態加載,那麼它的使用是可以的。

1

您可以將它用於提供API和XML配置文件的API,用戶可以在其中添加插件的類名。然後,是的,你可以使用這個