如何在Java中实现抽象的单例类?

Sim*_*mon 23 java inheritance singleton abstract-class classloader

这是我的示例抽象单例类:

public abstract class A {
    protected static A instance;
    public static A getInstance() {
        return instance;
    }
    //...rest of my abstract methods...
}
Run Code Online (Sandbox Code Playgroud)

以下是具体实施:

public class B extends A {
    private B() { }
    static {
        instance = new B();
    }
    //...implementations of my abstract methods...
}
Run Code Online (Sandbox Code Playgroud)

不幸的是我无法在B类中获取静态代码来执行,因此实例变量永远不会被设置.我试过这个:

Class c = B.class;
A.getInstance() - returns null;
Run Code Online (Sandbox Code Playgroud)

还有这个

ClassLoader.getSystemClassLoader().loadClass("B");
A.getInstance() - return null;
Run Code Online (Sandbox Code Playgroud)

在eclipse调试器中运行这两个,静态代码永远不会被执行.我可以找到执行静态代码的唯一方法是将B的构造函数的可访问性更改为public,并调用它.

我在Ubuntu 32bit上使用sun-java6-jre来运行这些测试.

Bal*_*usC 20

摘要单身人士?对我来说听起来不太可行.Singleton模式需要一个private构造函数,这已经使子类化成为不可能.你需要重新考虑你的设计.该抽象工厂模式可能更适合于特定的目的.

  • 对不起,但你的回答没用,ryvantage.私有构造函数是单例模式的关键要求.如果你没有,那么你实际上没有单身.阅读食物:http://butunclebob.com/ArticleS.UncleBob.SingletonVsJustCreateOne (6认同)

Ben*_*lli 8

从您的帖子开始,即使没有明确说明,听起来您希望抽象类扮演两个不同的角色.角色是:

  • (单例)服务的抽象工厂角色,可以有多个可替换的实现,
  • 服务接口角色,

另外,您希望服务在整个类的系列中是单例强制执行'singletoness',由于某种原因,它不足以缓存服务实例.

这可以.

有人会说它闻起来非常糟糕,因为"违反了关注点的分离","单身人士和单位测试并不能很好地结合在一起".

其他人会说这是好的,因为你赋予了在家庭中实例化正确的孩子的责任,并且整体上也暴露了更流畅的界面,因为你不需要调解工厂,除了暴露静态方法之外什么也不做.

有什么问题是你希望孩子们负责选择父工厂方法应该返回什么实现.这在设计方面是错误的,因为你委托给所有孩子,可以简单地将其推入并集中到抽象超类中,并且它还表明你正在混合使用在不同上下文中使用的模式,抽象工厂(父级决定什么类的类)客户将获得)和工厂方法(儿童工厂选择客户将获得的).

工厂方法不仅不是必需的,而且也不可能与工厂方法一起使用,因为它集中于实现或覆盖"实例"方法.对于静态方法,也没有构造函数的覆盖.

因此,回到一个抽象单例的初始好或坏的想法,选择要暴露哪些行为有几种方法来解决最初的问题,一个可能是以下,看起来很糟糕,但我想接近你正在寻找的:

public abstract class A{
    public static A getInstance(...){
      if (...)
         return B.getInstance();
      return C.getInstance();
    }

    public abstract void doSomething();

    public abstract void doSomethingElse();

}

public class B extends A{
    private static B instance=new B();

    private B(){
    }

    public static B getInstance(){
        return instance;
    }

    public void doSomething(){
        ...
    }
    ...
}

//do similarly for class C
Run Code Online (Sandbox Code Playgroud)

父母也可以使用反思.

更多测试友好和扩展友好的解决方案只是让孩子不是单身,而是打包成一些内部包,你将其记录为"私人"和抽象的父,可以暴露"单身模仿"静态getInstance()并将缓存孩子强制客户端始终获得相同服务实例的实例.