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

C#面试分享:单例模式的更多相关文章

  1. 2017、2018面试分享(js面试题记录)记得点赞分享哦;让更多的人看到~~

    2017面试分享(js面试题记录) 1. 最简单的一道题 '11' * 2 'a8' * 3 var a = 2, b = 3; var c = a+++b; // c = 5 2. 一道this的问 ...

  2. php程序猿面试分享

    面试总结 今天去了北京著名IT公司进行PHP程序猿的面试.这是人生第一次么,怎么不紧张?我是不是有病.不是.这叫自信呵. 首先是做一些笔试题. 1.mysql数据库索引使用的数据结构?这样做的优点是? ...

  3. 2020.4面试分享(7面收5个offer)

    都说金三银四是找工作的最佳时节,由于本人的个人职业规划跟目前工作内容不太相符(具体原因就不透露了,领导平时也要来这里逛,哈哈),四月份挑选了10多家公司投递简历(公司规模从几十人到上万人都有),参加了 ...

  4. 2020.4面试分享(7面收割5个offer)

    都说金三银四是找工作的最佳时节,由于本人的个人职业规划跟目前工作内容不太相符(具体原因就不透露了,领导平时也要来这里逛,哈哈),四月份挑选了10多家公司投递简历(公司规模从几十人到上万人都有),参加了 ...

  5. 阿里巴巴前端面试分享-社招(p6)

    借鉴了朋友的阿里面试经:(社招前端2年经验) 电话面 简单自我介绍, 做过哪些项目, 使用哪些技术栈 ? 如何看待前端框架选型 ? vue的如何实现双向绑定的 ? react 虚拟DOM 是什么? 如 ...

  6. cvte2018春招前端开发实习面试分享

    编程题问题描述: 返回整数数组中出现次数第n多的数字(返回值可能有多个) 最近在找实习,面试二面最后出了一道这样的编程题,当时有思路但语法有错误,而且很紧张,最后没有运行出来,导致凉凉,回来重新思考了 ...

  7. 太原面经分享:如何在vue面试环节,展示你晋级阿里P6+的技术功底?

    前言 一年一度紧张刺激的高考开始了,与此同时,我也没闲着,奔走在各大公司的前端面试环节,不断积累着经验,一路升级打怪. 最近两年,太原作为一个准二线城市,各大互联网公司的技术栈也在升级换代,假如你在太 ...

  8. java的设计模式 - 单例模式

    java 面试中单例模式基本都是必考的,都有最推荐的方式,也不知道问来干嘛.下面记录一下 饿汉式(也不知道为何叫这个名字) public class Singleton { private stati ...

  9. 太原面经分享:如何用js实现返回斐波那契数列的第n个值的函数

    面试攒经验,let's go! 值此高考来临之际,闲不住的我又双叒叕出发去面试攒经验了,去了公司交待一番流程后,面试官甩给了我一张A4纸,上面写着一道js算法笔试题(一开始我并不知道这是在考察js算法 ...

随机推荐

  1. MongoDB 复制机制

    一.复制原理 MongoDB的复制功能是使用操作日志oplog实现的,oplog包含主节点(Master)的每一次写操作,oplog是local本地数据库中的一个数据集合,其它非主节点(Seconda ...

  2. 时时监听input内容的改变

    心得:我们都知道input有一个change事件,但是是在input元素失去焦点的时候发生,不能时时的监听input内容的改变. 刚开始的时候我是想用setInterval设置计时器的原理定时监听in ...

  3. [Swift]LeetCode1011. 在 D 天内送达包裹的能力 | Capacity To Ship Packages Within D Days

    A conveyor belt has packages that must be shipped from one port to another within D days. The i-th p ...

  4. vue总结

    1.库和框架的区别 库:jquery 本质上就是一些列函数的集合,将一些函数封装到一个独立的就是文件中 在使用的jquery的时候,是由开发人员说了算的,也就是说开发人员起到了主导作用,而jquery ...

  5. vue-textarea 自适应高度

    需求简介 一个搜索页面,上面输入框,下面列表展示搜索到的结果. 重点是:产品要求搜索框默认显示一行,当输入的文字超过一行时,输入框的高度会随着改变,直到输入完毕. 解决思路设想 本想利用textare ...

  6. SpringBoot 集成Mybatis 连接Mysql数据库

    记录SpringBoot 集成Mybatis 连接数据库 防止后面忘记 1.添加Mybatis和Mysql依赖 <dependency> <groupId>org.mybati ...

  7. scala转换date提取年月日时分秒

    从数据库提取出来的时间为 String 格式,现在需要转换为 date 并提取出里面的 小时 时间段: import java.text.SimpleDateFormat import java.ut ...

  8. Python内置函数(63)——super

    英文文档: super([type[, object-or-type]]) Return a proxy object that delegates method calls to a parent ...

  9. RabbitMQ学习笔记(一) Hello World

    RabbitMQ是做什么的? RabbitMQ可以类比现实生活中的邮政服务. 现实中邮件服务处理的是邮件,发件人写好信件投入邮箱,邮递员收取信件存入邮局,邮局根据信件地址,分配邮递员投递信件到指定地点 ...

  10. 最快的进程间通信方式你get了么

    前言:天下武功为快不破!在信息爆炸.快速发展的新时代...,扯远了....进程间通信方式有很多,但最快的方式你知道么?由我娓娓道来... 一.共享内存方式 主角闪亮登场了,噔噔瞪...,最快的方式就是 ...