<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Mixin本意是指冰淇淋表面加的那些草莓醬,葡萄乾等點綴物,它們負責給冰淇淋新增風味。在OOP裡面也有Mixin這個概念,和它的本意相似,OOP裡面的Mixin意在為類提供一些額外功能——在不破壞類本身或者它的繼承鏈的基礎上,在某些情況下可能會起到妙用。今天跟著小編一起來看看吧。
試想我們在寫一個遊戲引擎,建立如下類:
class ScriptManager { public void AddScript(){/*省略實現*/} public void RemoveScript(){/*省略實現*/} } class EntityManager { public void AddEntity() {/*省略實現*/} public void RemoveEntity() {/*省略實現*/} } class AnimationManager { public void AddAnimationToWorld() {/*省略實現*/} public void RemoveAnimationFromWorld() {/*省略實現*/} }
程式碼非常簡單,三個manager類分別控制指令碼、實體和動畫。但是我們突然發現,這三個類應該都是單例才合適。按照我們之前在C#中的Singleton中介紹的方法,我們這麼改寫一下這三個類。
最簡單的,我們可以這麼改
class ScriptManager { private static ScriptManager _instance = null; public static ScriptManager Instance { get { if(_instance == null) { lock(typeof(ScriptManager)) { if(_instance == null) { _instance = new ScriptManager(); } } } return _instance; } } public void AddScript(){/*省略實現*/} public void RemoveScript(){/*省略實現*/} private ScriptManager() {/*省略實現*/} //車門焊死,不讓外部呼叫 } class EntityManager { //類似的修改方法 } class AnimationManager { //類似的修改方法 } static void Main(string[] args) { var instance1 = ScriptManager.Instance; var instance2 = ScriptManager.Instance; var result = instance1 == instance2; //true }
看起來沒有什麼問題,確實也滿足了可用的要求,但是僅僅可用是不夠的,我們想要更好的解決方案,而且這種修改方法雖然簡單,但如果我們想要修改的類不止這三個,或者,我們想要新增的不僅僅是單例方法,我們需要寫的程式碼會成倍增加,所以我們想要更好的解決方案。
很容易就能想到,既然這塊程式碼邏輯都是一樣的,我們為什麼不把它提煉到父類別?像這樣
class SingletonHolder<T> where T : class { private static T _instance = null; public static T Instance { get { if (_instance == null) { lock (typeof(T)) { if (_instance == null) { _instance = (T)Activator.CreateInstance(typeof(T), true); //呼叫非公有構造器 } } } return _instance; } } } class ScriptManager : SingletonHolder<ScriptManager> { //省略 } class EntityManager : SingletonHolder<EntityManager> { //省略 } class AnimationManager : SingletonHolder<AnimationManager> { //省略 } static void Main(string[] args) { var ScriptManager1 = ScriptManager.Instance; var ScriptManager2 = ScriptManager.Instance; var result = ScriptManager1 == ScriptManager2; //true var EntityManager1 = EntityManager.Instance; var EntityManager2 = EntityManager.Instance; result = EntityManager1 == EntityManager2; //true var AnimationManager1 = AnimationManager.Instance; var AnimationManager2 = AnimationManager.Instance; result = AnimationManager1 == AnimationManager2; //true }
確實可以,這樣就算有再多的類需要實現單例,只要讓它們繼承SingletonHolder就可以了,這樣的程式碼方便擴充套件也方便維護,畢竟功能邏輯都在父類別裡面。
不過仔細想想,這樣的程式碼還是有點問題,類繼承意味著子類應該是父類別的特化,代表著一種is-a的關係,但是我們這幾個Manager類和SingletonHolder並不是這種關係,它們和SingletonHolder更多像是一種實現契約的關係;如果一定要說is-a,它們應該是引擎模組(ModuleManager)的一種特化。所以讓它們繼承自SingletonHolder其實不是最好的方法,雖然語法正確、行為正確但是並不是語意正確,作為程式設計師,我們應該追求盡善盡美。而且未來真有可能會抽象出一個父類別ModuleManager,到時候就發現唯一的類繼承名額已經給SingletonHolder給佔用了,所以我們需要尋找一種既能注入邏輯程式碼,又不涉及類繼承的方法。
In object-oriented programming languages, a mixin (or mix-in) is a class that contains methods for use by other classes without having to be the parent class of those other classes. How those other classes gain access to the mixin's methods depends on the language. Mixins are sometimes described as being "included" rather than "inherited".
Mixins encourage code reuse and can be used to avoid the inheritance ambiguity that multiple inheritance can cause (the "diamond problem"), or to work around lack of support for multiple inheritance in a language. A mixin can also be viewed as an interface with implemented methods. This pattern is an example of enforcing the dependency inversion principle.
這是在Wiki上面Mixin的定義,允許程式設計師以在類繼承之外的方式為類新增一些方法,即,既能為類提供方法實現,又可以避免成為類的父類別,避免了類繼承和多重繼承所帶來的問題,這種概念正是我們需要的。
在C#中,它們通常以擁有實現的介面出現(default implementation interface from C#8.0),而在C#8.0之前,我們通常以輔助類的方式來實現Mixin,我們下面以這兩種方式改寫之前的類。
我們定義出一個介面,然後在外部基於這個介面實現單例邏輯(不用擴充套件方法是因為擴充套件方法不支援static method,如果想要注入的是非static method可以使用基於介面的擴充套件方法)
class SingletonHolder<T> where T : class, ISingleton { private static T _instance = null; public static T Instance { get { if (_instance == null) { lock (typeof(T)) { if (_instance == null) { _instance = (T)Activator.CreateInstance(typeof(T), true); } } } return _instance; } } } interface ISingleton { //沒有任何方法因為只是一個標記 } class ScriptManager : ISingleton { private ScriptManager() {/*省略實現*/} public void AddScript(){/*省略實現*/} public void RemoveScript(){/*省略實現*/} } class EntityManager : ISingleton { private EntityManager() {/*省略實現*/} public void AddEntity() {/*省略實現*/} public void RemoveEntity() {/*省略實現*/} } class AnimationManager : ISingleton { private AnimationManager() {/*省略實現*/} public void AddAnimationToWorld() {/*省略實現*/} public void RemoveAnimationFromWorld() {/*省略實現*/} } static void Main(string[] args) { var ScriptManager1 = SingletonHolder<ScriptManager>.Instance; var ScriptManager2 = SingletonHolder<ScriptManager>.Instance; var result = ScriptManager1 == ScriptManager2; //true var EntityManager1 = SingletonHolder<EntityManager>.Instance; var EntityManager2 = SingletonHolder<EntityManager>.Instance; result = EntityManager1 == EntityManager2; //true var AnimationManager1 = SingletonHolder<AnimationManager>.Instance; var AnimationManager2 = SingletonHolder<AnimationManager>.Instance; result = AnimationManager1 == AnimationManager2; //true }
這就是Mixin的用處,看起來這種實現方式的好處有:
從C#8.0開始,介面可以有方法的預設實現(包括static method),我們可以更加簡單的實現Mixin解決之前的問題
interface SingletonHolder<T> where T:class { private static T _instance = null; static T Instance { get { if(_instance == null) { lock(typeof(T)) { if(_instance == null) { _instance = (T)Activator.CreateInstance(typeof(T), true); } } } return _instance; } } } class ScriptManager : SingletonHolder<ScriptManager>{} class EntityManager : SingletonHolder<EntityManager>{} class AnimationManager : SingletonHolder<AnimationManager>{}
這就是Mixin以及它在C#中的簡單使用方法,希望通過這篇介紹能讓大家對這種用法有所瞭解,在想要給類新增程式碼邏輯但是又不想改變類內部或者影響類的繼承體系的時候,使用Mixin這種基於介面的程式碼邏輯注入也許能有奇效哦。
到此這篇關於聊聊C#中的Mixin的具體用法的文章就介紹到這了,更多相關C# Mixin用法內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45