【问题标题】:How to Inherit singleton如何继承单例
【发布时间】:2015-01-08 00:43:21
【问题描述】:

有时需要继承单例,但因为在单例中您使用的是无法覆盖的静态引用和静态方法。

例如(Java):

public class Singleton {
    private static Singleton instance = null;

    public static Singleton getInstance() {
        if (instance == null)
            instance = new Singleton();
        return instance;
    }
}

如果我用“SingletonChild”类继承“Singleton”,我将无法通过调用 getInstance() 方法生成实例。如果我将创建另一个 getInstanceChild() 方法,则基本方法:getInstance() 也将被公开。

【问题讨论】:

  • 真正的单例通常需要有一个private 构造函数。您将无法扩展该类。
  • Singleton 也会导致他们解决的更多问题,这就是为什么在大多数情况下它被认为是一种反模式。见this post。向它添加继承会使情况变得更糟恕我直言。
  • 单例的想法是你的系统中只有一个。当您从一个类继承时,您的对象仍然是父类的一个实例(多态)。因此,它的第二个实例将违反单例合同。也许你应该考虑你真正需要什么,而不是单例。
  • 考虑这一点:您正在编写一些具有一些全局功能的库作为单例,应该根据目标使用情况进行扩展。

标签: java design-patterns singleton


【解决方案1】:

您可以使用适配器模式并用另一个对象包装单例。如果你还让 Singleton 和 Adapter 共享一个接口,那么调用代码不必知道传递的是哪一个。

interface MyInterface{
    String foo();

    void bar();
}

public class Singleton implements MyInterface{
  //..same as before

}


public class Adapter implements MyInterface{
     private MyInterface delegate;

     public Adapter(MyInterface adaptMe){
        //check for null in real code
        this.delegate = adaptMe;
     }

     //delegate to bar
     public void bar(){
         delegate.bar();
     }

     //override foo
     public String foo(){
        return "AdaptedFoo";
     }
}

那么你的代码可以包装单例

MyInterface myInterface = new Adapter(Singleton.getInstance());

【讨论】:

  • 这确实是正确的解决方案,但是在这样的解决方案中,您必须在基类中实现和支持每个方法,这不是很方便。
  • 是的,这是真的。您可以使用 Java 做一些技巧来使用反射来委托调用,请参阅 Oracle 动态代理教程docs.oracle.com/javase/8/docs/technotes/guides/reflection/…
【解决方案2】:

一种方法是使用一个独立的工厂来创建这样的类,并确保它们确实是单身。但是这个解决方案有一个不同的问题,工厂必须知道使用基本“单例”的类的每个实现,或者必须扩展这个工厂才能获得这样的知识。

有一种不同的方法可以解决这个问题,让您在不修改工厂的情况下通过新实现继承单例。

public abstract class SingletonInheritance {
    public static abstract class AbstractSingleton {
        private static AbstractSingleton instance = null;

        protected AbstractSingleton() {
        }

        public static <T extends Class<? extends AbstractSingleton>>
        AbstractSingleton getInstance(T _class) {
            if (instance == null) {
                try {
                    instance = _class.getDeclaredConstructor().newInstance();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                }
            }
            return instance;
        }
    }

    public static class Singleton extends AbstractSingleton {
        public String foo() {
            return "Singleton";
        }
    }

    public static class SingletonChild extends Singleton {
        @Override
        public String foo() {
            return "SingletonChild";
        }
    }

    public static void main(String[] args) {
        SingletonChild singletonChild = 
            (SingletonChild) SingletonChild.getInstance(SingletonChild.class);
        System.out.println(singletonChild.foo());
    }
}

输出:“SingletonChild”

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-05
    相关资源
    最近更新 更多