在工厂模式中使用reflection

在工厂模式中使用Reflection是一个好习惯吗?

public class MyObjectFactory{ private Party party; public Party getObject(String fullyqualifiedPath) { Class c = Class.forName(fullyqualifiedPath); party = (PersonalParty)c.newInstance(); return party; } } 

PersonalParty实现派对

工厂模式的目的是将某些代码与其消耗的对象的运行时类型分离:

 // 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类型有什么不同? 最后你的代码就像耦合一样,但是你已经放弃了静态类型validation。 这意味着在放弃强类型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 

……那是不可扩展的。 由于此工厂创建的运行时类型的namename参数的值之间存在明显的可观察关系,因此应考虑使用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时都必须更改工厂对象 – 因此reflection解决方案或AbstractFactory是否是更好的解决方案实际上取决于您添加的频率和速度Party类型。 每天都有新型? 使用reflection。 每十年举办一次新派对? 使用AbstractFactory

以这种方式使用reflection(Class.forName)几乎总是标志着糟糕的应用程序设计。 有一些类型,它的使用是可以的,例如,如果你正在做一些外部库或插件的动态加载。

您可以将它用于API,您可以在其中提供API和XML配置文件,用户可以在其中添加其插件的类名。 然后,是的,你可以使用它