Java 在工厂模式中使用反射
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18432127/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using Reflection in factory pattern
提问by Ullas
Is it a good practice to use Reflection in Factory pattern?
在工厂模式中使用反射是一个好习惯吗?
public class MyObjectFactory{
private Party party;
public Party getObject(String fullyqualifiedPath)
{
Class c = Class.forName(fullyqualifiedPath);
party = (PersonalParty)c.newInstance();
return party;
}
}
PersonalParty implements Party
PersonalParty 实现 Party
采纳答案by Richard JP Le Guen
The purpose of the factory pattern is to de-couple some code from the run-time type of an object it consumes:
工厂模式的目的是将一些代码与其消耗的对象的运行时类型分离:
// This code doesn't need to know that the factory is returning
// an object of type `com.example.parties.SurpriseParty`
AbstractParty myParty = new PartyFactory().create(...);
Using code like this, the PartyFactory
is exclusively responsible for determining or knowing exactly what run-time type should be used.
使用这样的代码,PartyFactory
它专门负责确定或确切知道应该使用什么运行时类型。
You're forgoing that benefit by passing in the fully qualified name of the class you need. How is this...
通过传入所需的类的完全限定名称,您放弃了这种好处。这怎么样...
// This code obviously DOES know that the factory is returning
// an object of type `com.example.parties.SurpriseParty`.
// Now only the compiler doesn't know or enforce that relationship.
AbstractParty myParty = new PartyFactory().create("com.example.parties.SurpriseParty");
... any different from simply declaring myParty
as being of type com.example.parties.SurpriseParty
? In the end your code is just as coupled, but you've given up static type verification. That's means you're incurring less than no benefit while surrendering some of the benefits of Java being strongly typed. If you delete com.example.parties.SurpriseParty
your code will still compile, your IDE will give you no error messages and you won't realize there was a relationship between this code and com.example.parties.SurpriseParty
until run time - that's bad.
...与简单地声明myParty
为 type 有com.example.parties.SurpriseParty
什么不同?最后,您的代码同样耦合,但您已经放弃了静态类型验证。这意味着在放弃 Java 强类型的一些好处的同时,您获得的好处几乎没有。如果你删除com.example.parties.SurpriseParty
你的代码仍然可以编译,你的 IDE 不会给你任何错误消息,你不会意识到这段代码之间存在关系,com.example.parties.SurpriseParty
直到运行时 - 这很糟糕。
At the very least, I'd advise you to at least change this code so the method's argument is a simple class name, not a fully qualified name:
至少,我建议您至少更改此代码,以便该方法的参数是一个简单的类名,而不是一个完全限定的名称:
// I took the liberty of renaming this class and it's only method
public class MyPartyFactory{
public Party create(String name)
{
//TODO: sanitize `name` - check it contains no `.` characters
Class c = Class.forName("com.example.parties."+name);
// I'm going to take for granted that I don't have to explain how or why `party` shouldn't be an instance variable.
Party party = (PersonalParty)c.newInstance();
return party;
}
}
Next: is it bad practice to use Class.forName(...)
? That depends on what the alternative is, and the relationship between those String
arguments (name
) and the classes this factory will provide. If the alternative is a big conditional:
下一个:使用 是不好的做法Class.forName(...)
吗?这取决于替代方案是什么,以及这些String
参数 ( name
) 与该工厂将提供的类之间的关系。如果替代方案是一个很大的条件:
if("SurpriseParty".equals(name) {
return new com.example.parties.SurpriseParty();
}
else if("GoodbyeParty".equals(name)) {
return new com.example.parties.GoodbyeParty();
}
else if("PartyOfFive".equals(name)) {
return new com.example.parties.PartyOfFive();
}
else if(/* ... */) {
// ...
}
// etc, etc etc
... that's not scalable. Since there is an obvious observable relationship between the names of the run-time types this factory creates and the value of the name
argument, You should consider using Class.forName
instead. That way your Factory
object is protected from needing a code change every time you add a new Party
type to the system.
......那是不可扩展的。由于此工厂创建的运行时类型的名称与name
参数的值之间存在明显的可观察关系,因此您应该考虑Class.forName
改用。这样,Factory
每次Party
向系统添加新类型时,您的对象就不会需要更改代码。
Something else you could consider is using the AbstractFactory
pattern instead. If your consuming code looks like this:
您可以考虑的其他事情是使用该AbstractFactory
模式。如果您的消费代码如下所示:
AbstractParty sParty = new PartyFactory().create("SurpriseParty");
AbstractParty gbParty = new PartyFactory().create("GoodByeParty");
... where there are a limited number of often-occurring party types which are requested, you should consider having different methods for those different types of parties:
...如果请求的经常出现的聚会类型数量有限,您应该考虑为这些不同类型的聚会使用不同的方法:
public class PartyFactory {
public Party getSurpriseParty() { ... }
public Party getGoodByeParty() { ... }
}
... which will allow you to leverage Java's static typing.
...这将允许您利用 Java 的静态类型。
This solution does, however, mean that every time you add a new type of Party
you have to change the factory object - so whether the reflective solution or the AbstractFactory
is a better solution really depends on how often and how quickly you'll be adding Party
types. A new type every day? Use reflection. A new party type every decade? Use an AbstractFactory
.
但是,此解决方案确实意味着每次添加新类型时Party
都必须更改工厂对象 - 因此反射解决方案还是AbstractFactory
更好的解决方案实际上取决于您添加Party
类型的频率和速度。每天一个新类型?使用反射。每十年一个新的政党类型?使用AbstractFactory
.
回答by Martin Perry
Using reflection it this way (Class.forName) is almost always sign of bad application design. There are some kinds, where its use is OK, for example if you are doing some kind of dynamic load of external libraries or plugins.
以这种方式使用反射 (Class.forName) 几乎总是糟糕的应用程序设计的标志。有一些种类,它的使用是可以的,例如,如果您正在对外部库或插件进行某种动态加载。
回答by Jeroen Ingelbrecht
You could use it for an API where you provide an API and an XML configfile where users can add the classnames of their plugin. Then, yes, you could use this
您可以将它用于提供 API 和 XML 配置文件的 API,用户可以在其中添加其插件的类名。那么,是的,你可以使用这个