将属性传递给工厂方法
我有一个工厂方法,它返回接口的实现。事情是 - 实现具有不同的构造函数参数。将属性传递给工厂方法
我的问题是 - 如何通过工厂方法传递参数到接口的不同实现?
我有一个想法,但我不知道是否有道理 - 将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没有参数)。如果某些属性不存在,则可以传递一个默认值(如果该算法中需要该值)。
正如你所看到的,我希望能够动态地改变算法。用户将在运行时选择算法并传递适当的参数,这些参数将被放入属性对象中。
这是否合理?
更新编辑的问题(rev43552065-8ee8-47e8-bc96-c660c3836998):
你举的例子不是典型的工厂模式。如果您有三种算法需要按名称引用并为特定算法提供特定参数,为什么要使用工厂?您应该阅读着名的“Effective Java”一书中的“Item 1:考虑静态工厂方法而不是构造函数”。它描述了工厂方法的优点,这些在我的例子中都看不到。
这个问题有很多解决方案,您可以在各种热门项目中找到数百个示例。
例如,DriverManager
类,使用其中包含的可变格式连接细节和与高级选项(example)的附加Properties
对象的URL状字符串。
工厂方法通常应该足够抽象以获得工作实现,而无需为特定实现指定任何附加参数。它应该“隐藏”实施细节。
如果事实证明有必要传递其他/可选属性,则通常会传递一个Properties
对象。
有不同的策略。例如,UrlConnection
是一个抽象类。可以通过调用URL.openConnection()
来检索实例,但是,只能通过将返回的UrlConnection
转换为特定的子类型来设置许多选项。 HttpUrlConnection
。
我相信没有适合所有情况的单一解决方案,并且我相信很多解决方案(甚至可能在Java标准库中)都远非完美,但您应该真正实现一些简单而不是浪费的东西很多时间遇到这样的问题。
谢谢你的解释和例子。你能否考虑我编辑的问题,看看你是否仍然坚持你的回答? – Marko
@Marko我编辑了我的答案,以回应您的更新问题。 –
一种可能的方式,这是更类型安全不是通过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();
}
}
谢谢你的回答,但这不是我的目标。我实际上没有算法族,但是接口的实现不同。 – Marko
我看到战略模式更适合这里。你不需要传递参数给构造函数。它们看起来像是用于计算的参数。
如果您的算法使用相同的工作,例如计算税款,那么可以这样做。但是如果他们做了不同的事情 - 考虑使用其他方法或提供更多细节来看看可以做些什么。
因此,对于税收的计算可以这样:
taxCalculator = taxCalculatorFactory.Get(currentCountry);
taxAmount = taxCalculator.Calculate(countrySpecificTaxProperties);
只需使用一些界面为你countrySpecificTaxProperties,例如ITaxParams
我认为你需要实现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();
}
怎么样超载工厂方法? –
只有接口实现的属性才会有所不同,或者它们是否因呼叫而异? – dbugger
如果您需要将不同数量的参数传递给构造函数,最有可能您的设计不完美。如果你提供两个不同参数类的例子,这将是非常好的 –