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