是否可以将继承应用于Singleton类?

时间:2010-05-05 12:04:23

标签: java design-patterns singleton

今天我在采访中遇到了一个问题。是否可以在Singleton类上应用继承概念?我说因为构造函数是私有的,所以我们不能扩展那个Singleton类。

他问我的下一件事是在Singleton类上应用继承。因此,我将Singleton的构造函数视为受保护的思想,即child的构造函数也受到保护。但我错了,孩子的修饰符可能等于或高于此值。

所以,我请他就这种情况给出一个真实世界的例子。他无法给我一个,并说我无法提出问题,并希望我告诉他们这种情况是否可能。

我有点空白。我的问题是,

  • 这可能吗?
  • 即使有可能,它的用途是什么?
  • 现实世界的场景需要这样的用途?

8 个答案:

答案 0 :(得分:11)

,这在技术上是可行的,因为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;
    }       
}

编辑:正如Eyal在下面的评论中指出的那样,超级类中的构造函数必须受到保护(而不是私有),否则它们将不会被子类和代码甚至不会编译。

答案 1 :(得分:11)

引用bible

  

[...]时使用Singleton模式   唯一的实例应该是可扩展的   通过子类化,客户端应该是   能够使用扩展实例   没有修改他们的代码。

     

Singleton模式有几个   好处:[...]   3.允许改进业务和代表。单身人士   class可以是子类,也可以是   易于配置应用程序   这个扩展类的一个实例。   您可以使用配置应用程序   您需要的类的实例   运行时间。

至于如何实现这一点:本书提出了几种方法,其中最复杂的是注册表,其中的实例按名称查找。

答案 2 :(得分:10)

您可以使用一堆公共属性和方法创建一个抽象基类,然后创建一些子类作为单例类。那就是“以一种有用的方式应用继承概念”。

但是你不能做的是创建一个严格实现的单例类的子类。如果将单例类构造函数声明为private,则子类将无法编译。如果您使用其他访问权限声明它,则可以在另一个类中使用构造函数来创建多个实例...因此,它不是严格意义上的单例。如果你将单例声明为abstract,则根本无法实例化...因此它不是单例。

答案 3 :(得分:4)

它可能真的能够共同攻击任何东西,但在这种情况下它并不是真的可行。没有真正的理由将单例模式与继承一起使用,它只是不适合它。

答案 4 :(得分:3)

私有构造函数对该单例类的其他内部类是可见的。所以是的,从技术上讲,带有私有构造函数的单例类可以通过其内部类进行扩展。但为什么你会这样做的事情超出我的范围。

答案 5 :(得分:2)

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

};

答案 6 :(得分:1)

我猜这不是他不想要的,但如果你想获得技术,你也可以提到Singleton是一种模式,而不是一种实现。使用类构造函数不是获得Singleton的唯一方法,您可以让工厂强制执行该模式,在这种情况下,您可以使用与其他类完全相同的方式继承。

答案 7 :(得分:-2)

您可以将构造函数包设为私有。这样,包外的任何类都不能实例化Singleton类,但派生类可以调用上层构造函数。

但是,正如其他人所说,这实际上是不可取的。

顺便说一句愚蠢的面试问题。