在实现接口的类上强制单例模式

时间:2009-07-30 12:30:13

标签: java interface singleton design-patterns factory

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

现在我想强制 myxmlModel 以及模型的每个其他实现都遵循 Singleton Pattern 。通常的方法是使 myxmlModels 构造函数private并提供一个静态工厂方法来返回myModel类的实例。但问题是接口不能有静态方法定义,结果我不能强制执行特定的Factory方法定义所有模型的实现。因此,一个实现可能会以提供 getObject()结束,而其他实现可能会获得 NewModel()。

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

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

5 个答案:

答案 0 :(得分:4)

  1. 建立一个返回的工厂 您的界面实例,Model。
  2. 制作模型包私有类的所有具体实现 与您的工厂在同一个包装中。
  3. 如果您的模型是单身,并且您正在使用java 5+,使用枚举而不是传统 单身,因为它更安全。
  4. 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(); }
    }
    

答案 1 :(得分: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)

实际上,我不太喜欢这段代码:)。首先,它使用反射 - 非常慢,第二 - 如果类的定义错误,则存在运行时错误的可能性。

答案 2 :(得分:0)

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

答案 3 :(得分:0)

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

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

我通常使用Spring来实现这样的对象, 并且Spring配置使它成为Singleton。 安全,如此简单......加上额外的Spring优势(例如Proxying,替换一个不同的对象进行一些测试等等)

答案 4 :(得分:0)

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

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

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

public interface ModelFactory {

  public Model getModelInstance();

}

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

如果我猜错了,请留言并删除答案;)