2013-04-12 59 views
0

首先,我不知道如何打電話給我的問題,所以任何建議更好的標題請讓我知道。動態選擇一個類

我想創建一個接口,以便其他人可以添加他們的實現,然後在運行時決定使用哪個實現。

即 我創建一個接口「食物」,並存在2個實現「早餐」和「午餐」。在實現中都有相同的方法名稱和相同的參數,我想讓用戶在運行時調用其中任何一個。 「makeFood()使用早餐」或「makeFood()使用午餐」。

一種可能性是隻編譯一個實現,但如果將來必須使用其他實現,則需要刪除.class文件。

或者我應該使用某種類型的繼承?

此外(不優先): 我不知道實現類名稱,所以有人可以創建「晚餐」或「secondBreakfast」。這會導致我陷入另一個困境,如果用戶請求尚未實現的「類」,該怎麼辦:S我總是可以假設用戶知道哪些實現可用。

+1

使用'工廠'策略,根據傳入的參數返回不同的'Food'實例, – hiway

+0

您是否已經實現了一個實現,只希望用戶選擇要使用哪一個,或者您希望用戶添加它自己的庫在運行時? – Don

+0

@Juan,如果用戶傳入一個無效的參數,你可以拋出一個異常,告訴用戶有多少種「食物」存在。 – hiway

回答

4

這聽起來像我的戰略模式將滿足您的需求(GOF - http://en.wikipedia.org/wiki/Strategy_pattern)。

我不清楚你想這是多麼動態。有兩個接口的實現和一個選擇器方法是最簡單的。但是你也可以儘可能動態地生成接口的實現,這可能會在這裏被殺死。無論哪種方式,戰略模式都可以抽象出這種複雜性,並使您能夠根據所需的任何運行時標準選擇不同的行爲。

這裏是動態加載類,假設你已經知道完全合格的類名和對象有一個無參數的構造函數的例子:

Class c = Class.forName("java.lang.Object"); 
Object o = c.newInstance(); 

System.out.println("o = " + o); 

,你將需要捕捉的錯誤這種情況是:InterruptedException,ClassNotFoundException,IllegalAccessException,InstantiationException;不少,但只是以相同的方式處理它們,並拒絕用戶選擇。

如果需要使用參數的構造函數,則:

Class c = Class.forName("java.lang.String"); 
Constructor cons = c.getConstructor(String.class); // the args here are the expected types for the constructor that you require on the class 
String s = (String) cons.newInstance("hello"); 

這將增加更多的例外,將有被抓:InterruptedException的,ClassNotFoundException的,IllegalAccessException,InstantiationException,NoSuchMethodException,的InvocationTargetException。但是,再次以與之前相同的方式拒絕用戶選擇。

+0

我不知道實現類名稱,所以有人可以創建「晚餐」或「第二次早餐」。這會讓我陷入另一種困境,如果用戶選擇一個尚未實現的「類」,該怎麼辦:S – Juan

+0

捕獲用戶想要什麼的「發現」標準是什麼?基於此,您可以使用反射在運行時動態加載類。如果不存在這樣的類,那麼用戶標準是無效的,並且該情況必須被處理。 –

+0

atm我正在考慮以類名作爲參數運行應用程序的用戶。因此,爲了我的理解,我會有接口,然後而不是加載所有實現,我只會加載使參數的類?可悲的是我習慣於使用IDE,所以我通常會使加載自動化。 – Juan

0

您似乎正在準確描述Java的interface。例如:

Food.java:

interface Food { 
    void makeFood(); 
} 

Breakfast.java:

class Breakfast implements Food { 
    void makeFood() { System.out.println("Breakfast."); } 
} 

午餐。Java的:

class Lunch implements Food { 
    void makeFood() { System.out.println("Lunch."); } 
} 

下面我們就Food兩種不同的實現,就像你說的。現在,我們可以通過構建要麼實現類的實例化對象Food

Food myFood = new Breakfast(); 

Food myFood = new Lunch(); 

沒有文件或類似的東西的刪除。希望讓事情更清楚。

+0

是的,所以這是interace的想法。問題是這樣的: Food myFood = new X(); /讓x在運行時由用戶定義。 如果(arg =午餐)新食物=新午餐(),我可以做,但如果有人決定實施晚餐會發生什麼?然後我必須重寫代碼。 – Juan

+1

你的意思是'用戶',他們將如何與系統交互?可以使用反射來在運行時動態檢測和實例化類。 –

+0

我生成主文件和接口。第二個人可以生成接口的實現,並且用戶可以編譯主要接口,接口和所有可用實現,然後運行程序並輸入實現類型「早餐」,「午餐」或X命名。 – Juan

1

如果您不知道類名並希望知道所有可用類,則需要在運行時獲取所有接口的實現。 這可以通過思考來實現:http://code.google.com/p/reflections/

看一看方法getSubTypesOf

如果你希望用戶提供它自己的實現和使用這一個,你有不同的選擇:

1)在啓動時閱讀提供的Jar,並使用預配置的安裝程序(例如使用Spring)進行依賴注入。用戶可以在應用程序啓動之前將完整的qialified類名寫入設置中。

2)使用插件機制,如ServiceLoader:http://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html或JSPF:http://code.google.com/p/jspf/

或者如果你想在運行時閱讀新的實現,你可以使用OSGi:http://en.wikipedia.org/wiki/OSGi(看看Apache Karaf,Eclipse Equinox和Apache Felix)。