在工厂模式中使用反射 [英] Using Reflection in factory pattern

查看:133
本文介绍了在工厂模式中使用反射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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实施派对

PersonalParty implements Party

推荐答案

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

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(...);

使用这样的代码, PartyFactory 是专门负责确定或确切知道应该使用什么样的运行时类型。

Using code like this, the PartyFactory is exclusively responsible for determining or knowing exactly what run-time type should be used.

您通过传递所需类的完全限定名称来放弃该好处。这是怎么回事......

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");

...与简单声明 myParty 类型为 com.example.parties.SurpriseParty ?最后你的代码就像耦合一样,但是你已经放弃了静态类型验证。这意味着在放弃强类型Java的一些好处的同时,你所获得的收益甚至没有任何好处。如果您删除 com.example.parties.SurpriseParty 您的代码仍将编译,您的IDE将不会给您任何错误消息,您将不会意识到此代码之间存在关联并且 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.

至少,我' d建议您至少更改此代码,以便方法的参数是一个简单的类名,而不是完全限定的名称:

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;
    }
}

下一篇:使用<$ c是不好的做法$ C>的Class.forName(...)?这取决于替代方案是什么,以及那些 String 参数( name )与此工厂将使用的类之间的关系提供。如果替代方案是一个很大的条件:

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:

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

...这是不可扩展的。因为这个工厂创建的运行时类型的名称与名称的值参数,您应该考虑使用 Class.forName 。这样就可以保护 Factory 对象免受需要每次向系统添加新的 Party 类型时,代码都会更改。

... 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.

你可以考虑的其他事情是使用 AbstractFactory 模式。如果您的消费代码如下所示:

Something else you could consider is using the AbstractFactory pattern instead. If your consuming code looks like this:

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() { ... }

}

...这将允许您利用Java的静态类型。

... which will allow you to leverage Java's static typing.

但是,这个解决方案确实意味着每次添加一个新类型的派对你必须更改工厂对象 - 所以反射解决方案或 AbstractFactory 是否是更好的解决方案这取决于您添加 Party 类型的频率和速度。每天都有新型?使用反射。每十年举办一次新派对?使用 AbstractFactory

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.

这篇关于在工厂模式中使用反射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆