4

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

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

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

4 回答 4

1

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

您的示例不是典型的工厂模式。如果您需要按名称引用三种算法并为特定算法提供特定参数,那么为什么要使用工厂?您可能应该阅读著名书籍“Effective Java”中的“第 1 项:考虑静态工厂方法而不是构造函数”。它描述了工厂方法的优点,在您的示例中我都看不到。


这个问题有很多解决方案,你可以在各种热门项目中找到数百个示例。

例如,DriverManager该类使用类似 URL 的字符串,其中包含可变格式的连接详细信息和Properties具有高级选项的附加对象(示例)。

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

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

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

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

于 2016-01-11T16:37:43.613 回答
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 语句的工厂方法,请查看此替代方法

但我希望达到相同结果的偏好是:

public static Algo newInstance(String algoClassType) {
    return Class.forName(algoClassType).newInstance();      
}
于 2016-01-12T19:26:59.710 回答
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();
    }
}
于 2016-01-11T16:45:30.233 回答
0

我看到策略模式更适合这里。您不需要将参数传递给构造函数。它们看起来像用于计算的参数。

如果您的算法使用相同的工作,例如计算税款,则可以采用这种方式。但如果他们做不同的事情 - 考虑使用其他方法或提供更多细节以查看可以做什么。

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

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

只需为您的 countrySpecificTaxProperties 使用一些接口,例如 ItaxParams

于 2016-01-12T09:30:01.683 回答