2015-01-07 2 views
-1

Иногда возникает потребность в наследовании singleton, но поскольку в singleton вы используете статический ссылочный и статический метод, которые нельзя переопределить.Как наследовать singleton

Например (Java):

public class Singleton { 
    private static Singleton instance = null; 

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

Если я унаследовал бы "Singleton" с "SingletonChild" класс я не смогу генерировать экземпляр с помощью вызова метода GetInstance(). Если я создам еще один метод getInstanceChild(), будет открыт базовый метод: getInstance().

+2

Истинный синглтон будет, как правило, должны иметь 'private' конструктора. Вы не сможете расширить этот класс. –

+1

Синглтоны также вызывают больше проблем, которые они решают, поэтому в большинстве случаев они считаются антитравами. См. [Этот пост] (http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons). Добавление наследования к нему делает его хуже ИМХО. –

+3

Идея одного синглета заключается в том, что в вашей системе есть только один. Когда вы наследуете класс, ваш объект все еще является экземпляром родительского класса (полиморфно). Таким образом, второй экземпляр будет нарушать синглтонный контракт. Возможно, вам стоит подумать о том, что вам действительно нужно, вместо сингла. – RealSkeptic

ответ

0

Один из способов - использовать отделенную фабрику, которая будет создателем таких классов и гарантирует, что они действительно синглы. Но с этим решением возникает другая проблема, фабрика должна знать о каждой реализации класса, использующей базовую «Singleton», или этот завод должен быть расширен, чтобы получить такие знания.

Существует другой подход, который позволит решить эту проблему и позволит вам наследовать singleton с новой реализацией без изменений фабрики.

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"

0

Вы можете использовать шаблон Adapter и обернуть синглтон с другим объектом. Если вы также используете 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()); 
+0

Это действительно правильное решение, но в таком решении вам придется реализовать и поддерживать каждый отдельный метод в базовом классе, который не очень удобен. – Kvant

+0

Да, это правда. Есть несколько трюков, которые вы можете сделать с Java, чтобы использовать отражение для делегирования вызовов, см. Учебник Oracle по динамическим прокси. Http://docs.oracle.com/javase/8/docs/technotes/guides/reflection/proxy.html – dkatzel

Смежные вопросы