简体   繁体   English

AbstractClass.getInstance()方法就是这种反模式

[英]AbstractClass.getInstance() method is this an anti-pattern

In some places where a class hierarchy is present and the top most base class is an abstract class there is a static getInstance() method in the abstract class. 在存在类层次结构且最顶层基类是抽象类的某些地方,抽象类中有一个静态getInstance()方法。 This will be responsible for creating the correct sub-class and returning it to the caller. 这将负责创建正确的子类并将其返回给调用者。 For example consider the below code. 例如,考虑以下代码。

public class abstract Product {

   public static Product getInstance(String aCode) {
       if ("a".equals(aCode) {
          return new ProductA();
       }
       return ProductDefault();
   }
   // product behaviour methods
}

public class ProductA extends Product {}

public class ProductDefault extends Product {}

In Java, java.util.Calendar.getInstance() is one place this pattern has been followed. 在Java中,java.util.Calendar.getInstance()是一个遵循此模式的地方。 However this means each time a new subclass is introduced one has to modify the base class. 但是,这意味着每次引入新的子类时都必须修改基类。 ie: Product class has to be modified in the above example. 即:在上面的例子中必须修改产品类。 This seems to violate the ocp principle. 这似乎违反了ocp原则。 Also the base class is aware about the sub class details which is again questionable. 基类也知道子类的详细信息,这也是有问题的。

My question is... 我的问题是......

  1. is the above pattern an anti-pattern ? 上面的模式是反模式吗?
  2. what are the draw-backs of using the above pattern ? 使用上述模式的缺点是什么?
  3. what alternatives can be followed instead ? 相反可以采用哪些替代方案?

The interface is not an anti-pattern. 界面不是反模式。 But the way you've implemented it is rather poor ... for the reason you identified. 但是你实现它的方式相当差......因为你确定的原因。 A better idea would be to have some mechanism for registering factory objects for each code: 更好的想法是为每个代码注册工厂对象的一些机制:

  • The Java class libraries do this kind of thing using SPIs and code that looks reflectively for "provider" classes to be dynamically loaded. Java类库使用SPI和代码来执行此类操作,这些代码反映了要动态加载的“提供程序”类。

  • A simpler approach is to have a "registry" object, and populate it using dependency injection, or static initializers in the factory object classes, or a startup method that reads class names from a properties file, etcetera. 一种更简单的方法是使用“注册表”对象,并使用依赖注入或工厂对象类中的静态初始化程序填充它,或者从属性文件中读取类名的启动方法,等等。

No it's not. 不,这不对。 It's more like factory method pattern http://en.wikipedia.org/wiki/Factory_method_pattern . 它更像是factory method pattern http://en.wikipedia.org/wiki/Factory_method_pattern Eg Calendar.getInstance(); 例如Calendar.getInstance(); . JDK is full of such examples. JDK充满了这样的例子。 Also reminds of Effective Java Item 1: Consider static factory methods instead of constructors 还提醒Effective Java Item 1: Consider static factory methods instead of constructors

There are a number of separate issues here. 这里有许多不同的问题。

getInstance is probably going to be a bad name. getInstance可能是一个坏名字。 You explicitly want a new object you can play around with. 你明确地想要一个可以玩的新对象。 "Create", "make", "new" or just leave that word out. “创造”,“制造”,“新”或只是留下这个词。 "Instance" is also a pretty vacuous word in this context. 在这种情况下,“实例”也是一个非常空洞的词。 If there is sufficient context from the class name leave it out, otherwise say what it is even if that is just a type name. 如果类名中有足够的上下文,请将其删除,否则说出它是什么,即使它只是一个类型名称。 If the method returns an immutable object, of is the convention ( valueOf in olden times). 如果该方法返回一个不可变的对象, of是约定( valueOf在古倍)。

Putting it in an abstract base class (or in an interface if that were possible) is, as identified, not the best idea. 如所确定的那样,将它放在抽象基类中(或者如果可能的话,在接口中)并不是最好的想法。 In some cases an enumeration of all possible subtypes is appropriate - an enum obviously and really not that bad if you are going to use visitors anyway. 在某些情况下,所有可能的子类型的枚举都是合适的 - 如果你打算使用访问者,那么明显而且真的不是那么糟糕。 Better to put it in a new file. 最好把它放在一个新文件中。

Anything to do with mutable statics is wrong. 与可变静力学有关的任何事情都是错误的。 Whether it is reusing the same mutable instance, registration or doing something disgusting with the current thread. 它是否重用相同的可变实例,注册或做一些令人厌恶的当前线程。 Don't do it or depend (direct or indirectly) on anything that does. 不要做或依赖(直接或间接)任何事情。

Based on the feedback i introduced a new ProductFactory class that took care of creating the correct Product. 根据反馈,我介绍了一个新的ProductFactory类,负责创建正确的产品。 In my case the creation of the correct product instance depends on an external context (i've put the product code for the purpose of simplicity.. in the actual case it might be based on several parameters.. these could change over time). 在我的情况下,正确的产品实例的创建取决于外部上下文(我为了简单起见而放置产品代码..在实际情况下,它可能基于几个参数......这些可能随着时间的推移而变化)。 So having a Product.getInstance() method is not that suited because of the reasons outlined in the question. 因此,由于问题中概述的原因,使用Product.getInstance()方法并不合适。 Also having a different ProductFactory means in the future.. Product class can become an interface if required. 同样具有不同的ProductFactory意味着将来。如果需要,产品类可以成为一个接口。 It just gives more extensibility. 它只是提供了更多的可扩展性。

I think when the creation of the object doesn't depend on an external context.. like in the case of Calendar.getInstance() it's perfectly ok to have such a method. 我认为当对象的创建不依赖于外部上下文时...就像Calendar.getInstance()的情况一样,拥有这样的方法是完全可以的。 In these situations the logic of finding the correct instance is internal to that particular module/class and doesn't depend on any externally provided information.. 在这些情况下,找到正确实例的逻辑是该特定模块/类的内部逻辑,并且不依赖于任何外部提供的信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM