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