2016-01-11 144 views
3

我有一個工廠方法,它返回接口的實現。事情是 - 實現具有不同的構造函數參數。將屬性傳遞給工廠方法

我的問題是 - 如何通過工廠方法傳遞參數到接口的不同實現?

我有一個想法,但我不知道是否有道理 - 將Properties對象傳遞給工廠方法?這樣,每個接口實現都可以獲得構造函數所需的屬性,而工廠接口將被統一。

這是否有意義,還是有更好的解決方案?

我決定加一個例子,所以我可以更好地澄清這個問題。假設我們有接口SomeAlgorithm,並且我們有具體的算法,其中每個算法可以具有不同的參數,例如,

SomeAlgorithm algo = new Algo1(); 
SomeAlgorithm algo = new Algo2(noOfIterations); 
SomeAlgorithm algo = new Algo3(precision, boundary); 

我希望能夠像做

SomeAlgorithm algo = AlgoFactory.getAlgo("algoName"); 

我的方法來處理不同的參數會

SomeAlgorithm algo = AlgoFactory.getAlgo("algoName", properties); 

然後,AlgoFactory可以通過相應的屬性具體算法的構造,如果算法有參數(例如,Algo1沒有參數)。如果某些屬性不存在,則可以傳遞一個默認值(如果該算法中需要該值)。

正如你所看到的,我希望能夠動態地改變算法。用戶將在運行時選擇算法並傳遞適當的參數,這些參數將被放入屬性對象中。

這是否合理?

+0

怎麼樣超載工廠方法? –

+0

只有接口實現的屬性纔會有所不同,或者它們是否因呼叫而異? – dbugger

+1

如果您需要將不同數量的參數傳遞給構造函數,最有可能您的設計不完美。如果你提供兩個不同參數類的例子,這將是非常好的 –

回答

1

更新編輯的問題(rev43552065-8ee8-47e8-bc96-c660c3836998):

你舉的例子不是典型的工廠模式。如果您有三種算法需要按名稱引用併爲特定算法提供特定參數,爲什麼要使用工廠?您應該閱讀着名的「Effective Java」一書中的「Item 1:考慮靜態工廠方法而不是構造函數」。它描述了工廠方法的優點,這些在我的例子中都看不到。


這個問題有很多解決方案,您可以在各種熱門項目中找到數百個示例。

例如,DriverManager類,使用其中包含的可變格式連接細節和與高級選項(example)的附加Properties對象的URL狀字符串。

工廠方法通常應該足夠抽象以獲得工作實現,而無需爲特定實現指定任何附加參數。它應該「隱藏」實施細節。

如果事實證明有必要傳遞其他/可選屬性,則通常會傳遞一個Properties對象。

有不同的策略。例如,UrlConnection是一個抽象類。可以通過調用URL.openConnection()來檢索實例,但是,只能通過將返回的UrlConnection轉換爲特定的子類型來設置許多選項。 HttpUrlConnection

我相信沒有適合所有情況的單一解決方案,並且我相信很多解決方案(甚至可能在Java標準庫中)都遠非完美,但您應該真正實現一些簡單而不是浪費的東西很多時間遇到這樣的問題。

+0

謝謝你的解釋和例子。你能否考慮我編輯的問題,看看你是否仍然堅持你的回答? – Marko

+0

@Marko我編輯了我的答案,以迴應您的更新問題。 –

0

一種可能的方式,這是更類型安全不是通過Properties周圍,以確定結果類型,就是用Abstract Factory模式,例如:

// we will be creating subtypes of Vehicle 
interface Vehicle { 
    void move(); 
} 
class Car implements Vehicle { 
    Car(String vehicleId, int seatsNumber) {} 
} 
class Motorcycle implements Vehicle { 
    Motorcycle(String vehicleId) {} 
} 
// ... via subtypes of VehicleFactory 
interface VehicleFactory<T extends Vehicle> { 
    T create(String vehicleId); 
} 
class FourSeatedCarFactory implements VehicleFactory<Car> { 
    @Override 
    public Car create(String vehicleId) { 
     return new Car(vehicleId, 4); 
    } 
} 
class MotorcycleFactory implements VehicleFactory<Motorcycle> { 
    @Override 
    public Motorcycle create(String vehicleId) { 
     return new Motorcycle(vehicleId); 
    } 
} 
class FactoryClient { 
    void useVehicle(VehicleFactory<?> factory) { 
     factory.create("COOL_PLATE_NAME").move(); 
    } 
} 
+0

謝謝你的回答,但這不是我的目標。我實際上沒有算法族,但是接口的實現不同。 – Marko

0

我看到戰略模式更適合這裏。你不需要傳遞參數給構造函數。它們看起來像是用於計算的參數。

如果您的算法使用相同的工作,例如計算稅款,那麼可以這樣做。但是如果他們做了不同的事情 - 考慮使用其他方法或提供更多細節來看看可以做些什麼。

因此,對於稅收的計算可以這樣:

taxCalculator = taxCalculatorFactory.Get(currentCountry); 
taxAmount = taxCalculator.Calculate(countrySpecificTaxProperties); 

只需使用一些界面爲你countrySpecificTaxProperties,例如ITaxParams

0

我認爲你需要實現Builder模式。

構建器模式是一種對象創建軟件設計模式。與抽象工廠模式和工廠方法模式不同,它們的目的是啓用多態性,構建器模式的目的是找到伸縮構造器反模式的解決方案[需要的引證]。

當對象構造函數參數組合的增加導致構造函數的指數列表時,會發生伸縮構造函數反模式。

構建器模式不是使用大量構造函數,而是使用另一個對象構建器,它逐步接收每個初始化參數,然後一次返回結果構造對象。

看看這個例子代碼。

class SomeAlgorithm{ 
    // Make it or class or interface 
} 
class Algo extends SomeAlgorithm{ 
    private int noOfIterations; 
    private double precision; 
    private double boundary; 

    public Algo(Builder builder){ 
     this.noOfIterations = builder.noOfIterations; 
     this.precision= builder.precision; 
     this.boundary= builder.boundary; 
    } 
    public String toString(){ 
     return new StringBuilder("Algo:Iterations:precision:boundary:").append(noOfIterations).append(":"). 
     append(precision).append(":").append(boundary).toString(); 
    } 
    static class Builder { 
     private int noOfIterations; // Mandatory parameter 
     private double precision = 1.0; // Optional parameter 
     private double boundary = 2.0; // Optional parameter 

     public Builder (int noOfIterations){ 
      this.noOfIterations = noOfIterations; 
     } 
     public Builder precision(double precision){ 
      this.precision = precision; 
      return this; 
     } 
     public Builder boundary(double boundary){ 
      this.boundary = boundary; 
      return this; 
     } 
     public Algo build(){ 
      return new Algo(this); 
     } 
    } 
} 
public class BuilderDemo{ 
    public static void main(String args[]){ 
     Algo algo = new Algo.Builder(2).precision(3.0).boundary(4.0).build(); 
     System.out.println(algo); 
     algo = new Algo.Builder(10).build(); 
     System.out.println(algo); 
    } 
} 

輸出:

java BuilderDemo 2 
Algo:Iterations:precision:boundary:2:3.0:4.0 
Algo:Iterations:precision:boundary:10:1.0:2.0 

如果你要實現工廠方法具有相同的一組構造&參數,無需if-else語句,看看this alternative

但我的偏好達到相同的結果是:

public static Algo newInstance(String algoClassType) { 
    return Class.forName(algoClassType).newInstance();  
}