在工厂模式中使用反射是一种好的做法吗?
public class MyObjectFactory{
private Party party;
public Party getObject(String fullyqualifiedPath)
{
Class c = Class.forName(fullyqualifiedPath);
party = (PersonalParty)c.newInstance();
return party;
}
}
PersonalParty 实现 Party
工厂模式的目的是将一些代码从它使用的对象的运行时类型中分离出来:
// 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(...);
使用这样的代码,PartyFactory
专门负责确定或确切知道应该使用哪种运行时类型。
传递所需类的完全限定名称将放弃该好处。这是怎么...
// 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");
...与简单地将 myParty
声明为 com.example.parties.SurpriseParty
类型有什么不同?最后你的代码是耦合的,但是你已经放弃了静态类型验证。这意味着您在放弃 Java 强类型化的一些好处的同时,几乎没有得到任何好处。如果您删除 com.example.parties.SurpriseParty
,您的代码仍会编译,您的 IDE 不会给您任何错误消息,您也不会意识到此代码与 com 之间存在关系。 example.parties.SurpriseParty
直到运行时 - 这很糟糕。
至少,我建议您至少更改这段代码,使方法的参数是一个简单的类名,而不是完全限定的名称:
// 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;
}
}
下一步:使用 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
...那是不可扩展的。由于此工厂创建的运行时类型的名称与 name
参数的值之间存在明显的可观察到的关系,因此您应该考虑改用 Class.forName
。这样,每次向系统添加新的 Party
类型时,您的 Factory
对象都不会需要更改代码。
您还可以考虑使用 AbstractFactory
模式代替。如果您的消费代码如下所示:
AbstractParty sParty = new PartyFactory().create("SurpriseParty");
AbstractParty gbParty = new PartyFactory().create("GoodByeParty");
...如果请求的频繁出现的派对类型数量有限,您应该考虑为这些不同类型的派对使用不同的方法:
public class PartyFactory {
public Party getSurpriseParty() { ... }
public Party getGoodByeParty() { ... }
}
...这将使您能够利用 Java 的静态类型。
但是,此解决方案确实意味着每次添加新类型的 Party
时都必须更改工厂对象 - 因此无论是反射解决方案还是 AbstractFactory
是一个更好的解决方案实际上取决于您添加 Party
类型的频率和速度。每天一个新类型?使用反射。每十年一种新的政党类型?使用 AbstractFactory
。