Можно ли применить наследование к классу Singleton? - PullRequest
20 голосов
/ 05 мая 2010

Сегодня я столкнулся с одним вопросом в интервью. Можно ли применить концепцию наследования в классах Singleton? Я сказал, что поскольку конструктор является закрытым, мы не можем расширять этот класс Singleton.

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

Итак, я попросил его привести пример из реальной жизни по такому случаю. Он не смог дать мне один и сказал, что я не могу задавать вопросы, и хотел, чтобы я сказал, возможен ли этот сценарий или нет.

Я остался безучастным. Мой вопрос здесь,

  • Возможно ли это?
  • Даже если это возможно, какая польза от этого?
  • Какой сценарий реального мира потребует такого использования?

Ответы [ 8 ]

11 голосов
/ 05 мая 2010

Ссылаясь на Библию :

Используйте шаблон Singleton, когда [...] единственный экземпляр должен быть расширяемым путем подклассов, и клиенты должны быть возможность использовать расширенный экземпляр без изменения их кода.

У шаблона Singleton есть несколько выгоды: [...] 3. Разрешает уточнение операций и представление. Синглтон класс может быть подкласс, и это легко настроить приложение с экземпляр этого расширенного класса. Вы можете настроить приложение с экземпляр класса, который вам нужен в время выполнения.

Что касается того, как реализовать это: книга предлагает несколько способов, наиболее изощренным из которых является реестр, в котором экземпляры ищутся по имени.

11 голосов
/ 05 мая 2010

Да , это технически возможно, так как синглтон - это шаблон проектирования, а не языковая конструкция, которая может иметь ограничения наследования. Я бы просто переопределил метод public [Object] getInstance() в дочерних классах (см. Ниже).

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

public class ParentSingleton {

    private static ParentSingleton instance;

    protected ParentSingleton() {
    }

    public static synchronized ParentSingleton getInstance() {
       if (instance == null) {
          instance = new ParentSingleton();
       }

       return instance;
    }

    public int a() {
       // (..)
    }       
}

public class ChildSingleton extends ParentSingleton {

    private static ChildSingleton instance;

    public static synchronized ParentSingleton getInstance() {
       if (instance == null) {
          instance = new ChildSingleton();
       }

       return instance;
    }       
}

РЕДАКТИРОВАТЬ : как указал Эйал в своих комментариях ниже, конструктор в суперклассе должен быть защищен (а не закрытым), иначе он не будет виден дочерним классам и коду даже не скомпилирует.

10 голосов
/ 05 мая 2010

Вы можете создать абстрактный базовый класс с набором общих атрибутов и методов, а затем создать несколько подклассов в виде одноэлементных классов. Это «применение концепции наследования» ... полезным способом.

Но вы не можете создать подкласс строго реализованного одноэлементного класса. Если вы объявляете конструктор синглтон-классов как private, подкласс не будет компилироваться. Если вы объявите его с другим доступом, конструктор может быть использован в другом классе для создания нескольких экземпляров ... поэтому он не является синглтоном. Если вы объявляете синглтон как abstract, его экземпляр вообще не может быть создан ... следовательно, это не синглтон.

4 голосов
/ 05 мая 2010

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

3 голосов
/ 17 июня 2010

Закрытый конструктор виден другим внутренним классам этого синглтон-класса. Так что да, технически одноэлементный класс с приватным конструктором может быть расширен его внутренним классом Но почему вы делаете что-то подобное, мне не под силу.

2 голосов
/ 10 мая 2010

Ниже приведена одна реализация шаблона синглтона, описанная в GOF о создании синглтона с наследованием. Здесь родительский класс должен быть изменен, чтобы добавить новый производный класс. Переменная окружения может использоваться для создания экземпляра соответствующего конструктора производного класса.

Mainfile – 1
#include <iostream>
#include <string>
#include "Singleton.h"
using namespace std;

int main(){

     Singleton::instant().print();
     cin.get();
}
Singleton.h
#pragma once
#include <iostream>
using std::cout;
class Singleton{
public:
    static Singleton & instant();
    virtual void print(){cout<<"Singleton";}
protected:
    Singleton(){};
private:
    static Singleton * instance_;
    Singleton(const Singleton & );
    void operator=(const Singleton & );

};

Singleton.cpp
#include "Singleton.h"
#include "Dotted.h"
Singleton * Singleton::instance_ = 0;
Singleton & Singleton::instant(){
    if (!instance_)
    {
        char * style = getenv("STYLE");
        if (style){
            if (strcmp(style,"dotted")==0)
            {
                instance_ = new Dotted();
                return *instance_; 
            }           else{
                instance_ = new Singleton();
                return *instance_;
            }       
        }

        else{
            instance_ = new Singleton();
            return *instance_;
        }
    }
    return *instance_;

}
Dotted.h

#pragma once
class Dotted;

class Dotted:public Singleton{
public:
    friend class Singleton;
    void print(){cout<<"Dotted";}
    private:
        Dotted(){};

};
1 голос
/ 05 мая 2010

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

0 голосов
/ 05 мая 2010

Вы можете сделать конструктор package-private. Таким образом, ни один класс вне пакета не может создать экземпляр класса Singleton, но производные классы могут вызвать конструктор верхнего класса.

Но, как говорили другие, это действительно не рекомендуется.

Глупый вопрос, кстати.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...