博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C#面试分享:单例模式
阅读量:5280 次
发布时间:2019-06-14

本文共 3017 字,大约阅读时间需要 10 分钟。

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 animali am animal

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

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

public class Animal{    private static readonly IDictionary
_dictionary = new ConcurrentDictionary
(); static Animal() { _dictionary.Add(typeof(Animal), new Animal()); } public static T GetInstance
() 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 cat = Animal.GetInstance
(); animal.Print(); cat.Print(); Console.ReadLine();}

输出:

i am Animali am Cat

转载于:https://www.cnblogs.com/ArthurRen/p/9570722.html

你可能感兴趣的文章
Java大数——a^b + b^a
查看>>
简单的数据库操作
查看>>
帧的最小长度 CSMA/CD
查看>>
普通求素数和线性筛素数
查看>>
PHP截取中英文混合字符
查看>>
电子眼抓拍大解密
查看>>
51nod1076 (边双连通)
查看>>
Linux pipe函数
查看>>
Zerver是一个C#开发的Nginx+PHP+Mysql+memcached+redis绿色集成开发环境
查看>>
程序的静态链接,动态链接和装载 (补充)
查看>>
关于本博客说明
查看>>
[Kaggle] Sentiment Analysis on Movie Reviews
查看>>
价值观
查看>>
mongodb命令----批量更改文档字段名
查看>>
国外常见互联网盈利创新模式
查看>>
android:scaleType属性
查看>>
shell脚本
查看>>
Upload Image to .NET Core 2.1 API
查看>>
【雷电】源代码分析(二)-- 进入游戏攻击
查看>>
Linux中防火墙centos
查看>>