我正在使用DI传递我的依赖项。但在某些情况下,我们需要动态创建对象,并且需要在初始化期间提供参数。 代码示例-a 尝试解释该方案。
为了初始化这种类型的对象并隐藏 new 运算符,我创建了简单的工厂。 代码示例-b 。
代码示例-a
int用于简化它们/实际上可以是某些真实对象
public class Sample {
private final int c;
public Sample(int c){
this.c = c;
}
public void doSomething(SomeCommand command, Request request, Context context){
DynamicDependency dynamicDependency = new DynamicDependency(command.getA(), command.getB(), c);
dynamicDependency.doSomeWork(request, context);
}
}
class DynamicDependency{
private final int a;
private final int b;
private final int c;
public DynamicDependency(int a, int b, int c){
this.a = a;
this.b = b;
this.c = c;
}
public void doSomeWork(Request request, Context context){
/*
Do work
*/
}
}
class SomeCommand {
private int a;
private int b;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public int getB() {
return b;
}
public void setB(int b) {
this.b = b;
}
}
代码示例-b
public interface IParameterizedObjectFactory<T> {
T getInstance(Object... arguments) throws ClassCastException;
}
public class DynamicDependency implements IParameterizedObjectFactory<DynamicDependency> {
@Override
public DynamicDependencyFactory getInstance(Object... arguments) throws ClassCastException {
Validate.notNull(arguments);
if(arguments.length > 0){
final int a = (Integer) arguments[0];
final int b = (Integer) arguments[1];
final int c = (Integer) arguments[2];
return new DynamicDependency(a, b,c);
}
return null;
}
}
这可以完成工作,因为我现在可以注入工厂,然后使用它来获取新对象:
DynamicDependency dynamicDependency = dynamicDependencyFactory.getInstance(a,b,c);
问题(S):
虽然,它完成了工作,但我们需要传递Object [s]的列表,并且我们放松了强类型。施法也会占用一些执行时间。如何改进?
另一种方法可能是根本不使用接口,并使用具有适当参数列表的getInstance方法的具体类。对我来说听起来很合理。
public class DynamicDependencyFactory {
public DynamicDependency getInstance(int a, int b, int c) {
return new DynamicDependency(a, b,c);
}
}
还可以采取哪些措施来隐藏新?或者我应该使用第二种方法来创建具体工厂?
注意:我正试图远离反思
答案 0 :(得分:0)
我决定使用混合方法,使用工厂,我无法控制正在创建的运行时对象,并通过控件与我一起的方法传递运行时数据。
史蒂文在评论中分享了几篇好文章,发布在这里。
Factories are a code smell runtime values should not be injected into a component's constructor
幸运的是,在运行时值的情况下,我已经避免了构造函数注入。问题在于遗留代码和我们团队不拥有的代码。对于现在,对于不属于我们的代码,我们必须使用构造函数,即使它会闻到一点:)
答案 1 :(得分:0)
你建议的第二种方法比第一种方法好得多。如果需要,您仍然可以从该工厂中提取接口:
public interface IDynamicDependencyFactory {
DynamicDependency getInstance(int a, int b, int c);
}
请注意缺少泛型类型参数。您对以下界面的第一个建议:
public interface IParameterizedObjectFactory<T> {
T getInstance(Object... arguments) throws ClassCastException;
}
根据您的示例,似乎完全没有必要,并且正如您所指出的那样,Object[]
作为参数使得它成为一个非常令人不愉快且非类型安全的API。
如果确实需要将不同的参数类型传递给工厂中的方法,那么为每个有效签名定义一个重载,而不是只接受Object[]
:
public interface IDynamicDependencyFactory {
DynamicDependency getInstance(int a, int b, int c);
DynamicDependency getInstance(double a, int b, BigDecimal c);
}
更好的是,如果您可以重构代码以便它不需要这样的工厂那么这可能是有益的(除非您无法同时访问Request
和Context
个对象时间为a
,b
和c
int
值。例如,您可以将构造函数参数拉出为方法参数,并将DynamicDependency视为服务(或单例):
class DynamicDependencyService {
public void doSomeWork(Request request, Context context, int a, int b, int c){
//Do work
}
}
这样,DynamicDependencyService
的实例可以通过构造函数传递给Sample
对象。