Подтвердить что ты не робот

Можно ли применить наследование к классу Singleton?

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

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

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

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

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

Ответ 1

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

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

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

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

Ответ 2

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

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

Ответ 3

Да, это технически возможно, поскольку singleton - это шаблон дизайна, а не языковая конструкция, которая может иметь ограничения наследования. Я бы просто переопределял метод 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;
    }       
}

EDIT: как отметил Эяль в своих комментариях ниже, конструктор суперкласса должен был быть защищен (вместо частного), иначе он не будет виден дочерним классам, а код даже не компилируется.

Ответ 4

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

Ответ 5

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

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(){};

};

Ответ 6

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

Ответ 7

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

Ответ 8

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

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

Глупый вопрос интервью между прочим.