将属性传递给Factory方法

时间:2016-01-11 16:26:35

标签: java design-patterns factory-pattern builder-pattern

我有一个工厂方法,它返回一个接口的实现。问题是 - 实现具有不同的构造函数参数。

我的问题是 - 如何通过工厂方法将参数传递给接口的不同实现?

我有一个想法,但我不确定它是否有意义 - 将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); 

然后,如果算法完全具有参数(例如Algo1没有参数),AlgoFactory可以将适当的属性传递给具体的算法构造函数。如果某些属性不存在,则可以传递默认值(如果算法中需要该值)。

如您所见,我希望能够动态更改算法。用户可以在运行时选择算法并传递适当的参数,这些参数将被放入属性对象中。

这会有意义吗?

4 个答案:

答案 0 :(得分:1)

已修改问题的更新(rev43552065-8ee8-47e8-bc96-c660c3836998):

您的示例不是典型的工厂模式。如果您需要通过名称引用三种算法并为特定算法提供特定参数,那么您为什么要使用工厂?您应该阅读"项目1:考虑静态工厂方法而不是构造函数"来自着名的书籍#34; Effective Java"。它描述了工厂方法的优点,我在你的例子中没有看到它们。

这个问题有很多解决方案,你可以在各种流行的项目中找到数百个例子。

例如,DriverManager类使用类似URL的字符串,其中包含变量格式的连接详细信息和带有高级选项(example)的其他Properties对象。

工厂方法通常应该足够抽象以获得有效的实现,而无需为特定实现指定任何其他参数。应该隐藏"隐藏"实施细节。

如果有必要传递附加/可选属性,则传递Properties对象是很常见的。

有不同的策略。例如,UrlConnection是一个抽象类。可以通过调用URL.openConnection()来检索实例,但是,只能通过将返回的UrlConnection转换为特定的子类型来设置许多选项,例如, HttpUrlConnection

我相信没有适合所有情况的单一解决方案,我很确定许多解决方案,甚至可能在Java标准库中,都远非完美,但你应该真正实现一些简单而不是浪费太多时间问题。

答案 1 :(得分: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();
    }
}

答案 2 :(得分:0)

我认为策略模式更适合此处。您不需要将参数传递给构造函数。他们看起来像params进行计算。

如果您的算法使用相同的工作,例如计算税,那么就可以这样做了。但如果他们做不同的事情 - 考虑使用其他方法或提供更多细节,看看可以做些什么。

因此,对于税收计算,它可以是:

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

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

答案 3 :(得分: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

如果必须使用相同的构造函数和参数集实现Factory方法如果没有if-else语句,请查看this alternative

但我对获得相同结果的偏好是:

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