欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C#面试分享:单例模式

程序员文章站 2022-05-04 14:01:59
C 面试分享:单例模式 提问1:请给出单例模式的实现: 答: 提问2:继承会破坏单例模式吗? 分析: 说实话,当时这个问题把我给问懵了,没有想明白面试官想考察什么。 下面参考《Head First 设计模式》一书的相关问题,来做一些分析: 首先,就上文的代码而言,子类可以继承 Animal 吗? 答 ......

c#面试分享:单例模式

提问1:请给出单例模式的实现:

答:

public class animal
{
    private static animal _instance = null;
    private static readonly object _lock = new object();

    public static animal instance
    {
        get
        {
            if (_instance == null)
            {
                lock (_lock)
                {
                    if (_instance == null)
                    {
                        _instance = new animal();
                    }
                }
            }
            return _instance;
        }
    }

    public string name { get; set; } = "animal"

    private animal() {}
        
    public void print()
    {
        console.writeline("i am " + name);
    }
}

提问2:继承会破坏单例模式吗?

分析:

说实话,当时这个问题把我给问懵了,没有想明白面试官想考察什么。

下面参考《head first 设计模式》一书的相关问题,来做一些分析:

首先,就上文的代码而言,子类可以继承 animal 吗?

答案显然是不能的,因为animal的构造函数是私有(private)的。为了不破坏单例模式"唯一实例,全局访问点"这两个约束条件,我们把构造器改为 protected ,这样子类就能顺利继承animal了。

第二点,我们假定所有的子类也是单例的,所以每个子类都应该实现 instance 这么一个全局访问点,以下代码实现了继承自 animal 的子类 cat 单例模式:

public class cat : animal
{
    private static cat _instance = null;
    private static readonly object _lock = new object();

    public new static cat instance
    {
        get
        {
            if (_instance == null)
            {
                lock (_lock)
                {
                    if (_instance == null)
                    {
                        _instance = new cat();
                    }
                }
            }
            return _instance;
        }
    }

    protected cat()
    {
        name = "cat";
    }
}

测试:

animal animal = animal.instance;
animal cat = cat.instance;

animal.print();
cat.print();

打印结果:

i am animal
i am animal

这种结果显然是有问题的,原因就在于子类 cat 的 instance 是用 new 修饰的,cat对象调用的instance属性其实还是父类 animal 的instance属性。

解决方法就是在父类中实现“注册器”,提供父类及其所有子类的“全局访问点”,以下就是修改后的父类 animal 代码:

public class animal
{
    private static readonly idictionary<type, animal> _dictionary = new concurrentdictionary<type, animal>();

    static animal()
    {
        _dictionary.add(typeof(animal), new animal());
    }

    public static t getinstance<t>() where t : animal
    {
        var type = typeof(t);
        if (!_dictionary.containskey(type))
        {
            var constructors = type.getconstructors(bindingflags.instance | bindingflags.nonpublic);
            var constructor = constructors[0];
            var animal = constructor.invoke(null) as animal;
            _dictionary.add(type, animal);
            return animal as t;
        }
        return _dictionary[type] as t;
    }

    public string name { get; protected set; }

    protected animal()
    {
        name = "animal";
    }
        
    public void print()
    {
        console.writeline("i am " + name);
    }
}

cat代码

public class cat : animal
{
    protected cat()
    {
        name = "cat";
    }
}

测试:

static void main(string[] args)
{
    animal animal = animal.getinstance<animal>();
    animal cat = animal.getinstance<cat>();
    animal.print();
    cat.print();

    console.readline();
}

输出:

i am animal
i am cat