6

我最好用一个例子来解释这个问题。我有一个可用于访问数据的接口模型。Model 可以有不同的实现,可以表示各种格式的数据,比如 XMl、txt 格式等。Model关心格式。可以说一种这样的实现是myxmlModel

现在我想强制myxmlModelModel的所有其他实现遵循单例模式。通常的方法是使myxmlModels构造函数私有并提供静态工厂方法来返回 myModel 类的实例。但问题是接口不能有静态方法定义结果我无法对Model的所有实现强制执行特定的 Factory 方法定义。因此,一种实现可能以提供getObject()结束,而另一种实现可能已经获得NewModel()。.

一种解决方法是允许包访问myxmlModel 的构造函数并创建一个 Factory 类,该类创建myxmlModel对象并将其缓存以供进一步使用。

我想知道是否有更好的方法来实现相同的功能。

4

5 回答 5

4
  1. 创建一个返回接口实例的工厂,模型。
  2. 在与您的工厂相同的包中制作模型包私有类的所有具体实现。
  3. 如果您的模型是单例,并且您使用的是 java 5+,请使用枚举而不是传统的单例,因为它更安全。
public enum MyXMLModel{  
INSTANCE();  
//rest of class  
};

编辑:另一种可能性是创建完成所有工作的委托类,然后使用枚举来提供所有模型选项。

例如:

class MyXMLModelDelegate implements Model {
public void foo() { /*does foo*/}
...
}

class MyJSONModelDelegate implements Model {
public void foo() { /*does foo*/ }
...
}

public enum Models {
XML(new MyXMLModelDelgate()),
JSON(new MyJSONModelDelegate());

private Model delegate;
public Models(Model delegate) { this.delegate=delegate; }

public void foo() { delegate.foo(); }
}
于 2009-07-30T12:36:20.250 回答
2

您可以使用反射。像这样的东西:

public interface Model {
  class Singleton {
    public static Model instance(Class<? extends Model> modelClass) {
      try {
        return (Model)modelClass.getField("instance").get(null);
     } catch (blah-blah) {
       blah-blah
     }
  }
}

public class XmlModel implements Model {
  private static final Model instance = new XmlModel();

  private XmlModel() {
  }
}

用法:

Model.Singleton.instance(XmlModel.class)

实际上,我不太喜欢这段代码:)。首先,它使用反射 - 非常慢,其次 - 如果类定义错误,则可能会出现运行时错误。

于 2009-07-30T15:10:21.020 回答
0

您可以将接口重构为抽象类吗?这将允许您将特定的工厂方法强制到所有实现类。

于 2009-07-30T12:33:23.697 回答
0

我曾经问过自己同样的问题。我提出了相同的答案;-)

现在我通常放弃“强迫”行为,我依赖文档。我没有发现 Singleton 方面如此引人注目以至于需要通过各种方式强制执行的情况。这只是该项目的“最佳实践”。

我通常使用 Spring 来实例化这样的对象,正是 Spring 配置使其成为 Singleton。安全,如此简单......加上额外的 Spring 优势(例如代理,一次替换不同的对象以进行一些测试等......)

于 2009-07-30T12:39:19.577 回答
0

这更像是对您对 kts 答案的评论/澄清的答案。是不是这样,真正的问题不是使用单例模式,而是定义一个允许贡献单例的 Eclipse(Equinox)扩展点模式?

我认为,这无法完成,因为每次调用 IConfigurationElement.createExecutableExtension 时都会创建一个新实例。这与您的单例要求完全不兼容。因此,您需要公共默认构造函数,以便每个人都可以创建实例。

除非您可以更改扩展点定义以便插件贡献 ModelFactory 而不是模型,例如

public interface ModelFactory {

  public Model getModelInstance();

}

因此扩展用户将实例化一个 ModelFactory 并使用它来获取单例。

如果我猜错了,请发表评论,我会删除答案;)

于 2009-07-30T13:27:30.867 回答