單例模式
有關單例模式本身,我想就不用我在這裡多說了,它可以說是模式中最簡單的一個了。我只是想談談我對這個模式的一點想法。
為了實現單例模式,我們通常的做法是,在類中定義一個方法如GetInstance,判斷如果實例為null則新建一個實例,否則就返回已有實例。但是我覺得這種做法將對象的生命周期管理與類本身耦合在了一起,與SRP原則相違背。所以我覺得遇到需要使用單例的地方,應該將生命周期管理的職責轉移到對象容器上,而我們的類依然是一個干淨的類。
為了接下來的說明,我們先編寫幾個後面需要的接口和類:准備工作
IOrder接口、CommonOrder類、VipOrder類:
將Unity應用於單例模式,主要有兩種使用場景:
(1)將類型注冊為單例;
(2)將已有對象注冊為單例。
將類型注冊為單例
與上一篇文章建立類型映射類似,我們可以將一個接口注冊為標識鍵,對應一個具體類。不同的是,要用於單例模式,我們需要使用一個LifetimeManager類型的參數,並指定為ContainerControlledLifetimeManager類型:
RegisterType<TFrom, TTo>(new ContainerControlledLifetimeManager())
以下的代碼以接口注冊為例,演示了如何為一個接口注冊一個具體類,並聲明為單例:
同樣,我們可以為一個基類注冊一個具體類,與前述的類似,如:container.RegisterType<Order, CommonOrder>(new ContainerControlledLifetimeManager());我們還可以把某個類直接注冊為單例,而不進行類型的映射,如:container.RegisterType<CommonOrder>(new ContainerControlledLifetimeManager());
這裡需要指出的是:默認情況下,直接使用RegisterType(不指定LifetimeManager),然後Resolve所得到的對象的生命周期是短暫的,容器並不保存對象的引用,每次調用Resolve方法我們都會得到一個新對象。然而,當我們指定了ContainerControlledLifetimeManager參數後,容器在第一次調用Resolve方法時會創建一個新對象,此後在每次調用Resolve時,都會返回之前創建的對象。
除此之外,Unity還擴展了單例的使用方式。例如,我需要把某個類設計為單例,但是發現在應用中我們需要這個類的兩個單例,分別有不同的用途,這時,使用Unity的類型與名稱組合的標識鍵,就可以滿足這種使用場景。使用方式如下(以接口為例):
ps:使用類型與名稱的組合的例子可以參見前面一篇文章,大致相同。
同理,我們也可以用基類和名稱的組合為標識鍵注冊具體類,還可以直接把某個類和名稱組合進行注冊。這裡不再贅述。
將已有對象注冊為單例
如果我們已經創建了一個對象,並希望使用已創建的對象作為單例,而不是由容器新創建一個對象,那麼我們應該使用RegisterInstance方法。以下的代碼以接口注冊為例,演示了如何使用一個已有對象,為一個接口注冊一個具體類,並聲明為單例:
將已有對象注冊為單例,同樣也支持前面提到的幾種使用方式,如注冊基類、使用名稱等,也就不再重復了。