java - 在工厂模式中使用反射

标签 java reflection factory 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 实现 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

关于java - 在工厂模式中使用反射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18432127/

相关文章:

c++ - 扩展此 C++ 工厂实现的最佳方法?

php - 如何在数据库播种器中将参数传递给 laravel 工厂?

java - 获取元素而不迭代

java - 如何在 Java 中实现 C 的结构?

java - 在Windows 7 64位以及Java 8和Maven3.3.3上构建hadoop 3.0.0-SNAPSHOT时出现问题

c# - 反射不触发参数化构造函数c#

java - 从字符串中提取电话号码

python - 在 python 中发现装饰类实例方法

java - 如何为 jar 中的每个类获取 Class 对象

c# - DDD、AutoMapper 和工厂