摘要:而且修改老代碼,大大增加了出現(xiàn)的概率。這里菜菜再?gòu)?qiáng)調(diào)一遍架構(gòu)設(shè)計(jì)的一項(xiàng)重要原則類應(yīng)該對(duì)修改關(guān)閉,對(duì)擴(kuò)展開放。附加在對(duì)象最外層的行為,不應(yīng)該窺視被包裝的類型內(nèi)部的一些特性?;谝陨系脑O(shè)計(jì)思想,擴(kuò)展的行為完全有能力修改,覆蓋玩家的某些行為。
初級(jí)版本
這是玩家的抽象基礎(chǔ)類,這個(gè)設(shè)計(jì)很好,把一些玩家共有的特性抽象出來(lái)
//玩家的基礎(chǔ)抽象類 abstract class Player { //玩家的級(jí)別 public int Level { get; set; } //其他屬性代碼省略一萬(wàn)字 }
這是新加需求:10級(jí)可以跳躍,具體跳躍動(dòng)作是客戶端做處理
//玩家的基礎(chǔ)抽象類 abstract class Player { //玩家的級(jí)別 public int Level { get; set; } //其他屬性代碼省略一萬(wàn)字 //新加玩家跳躍動(dòng)作,由于需要到達(dá)10級(jí)所以需要判斷l(xiāng)evel public virtual bool Jump() { if (Level >= 10) { return true; } return false; } }
這種代碼初級(jí)人員很容易犯,有什么問題呢?
跳躍的動(dòng)作被添加到了基類,那所有的子類就都有了這個(gè)行為,如果子類機(jī)器人玩家不需要這個(gè)跳躍的行為呢?
為了新需求,修改了基類,如果每次需求都需要修改基類,時(shí)間長(zhǎng)了,項(xiàng)目大了,這個(gè)是比較要命的。
優(yōu)化版本由于需求是增加玩家一個(gè)行為,根據(jù)上一節(jié)的介紹,我們應(yīng)該了解到,行為在代碼級(jí)別更傾向于用接口來(lái)表示。而且不是所有的玩家類型都需要附加跳躍這個(gè)行為。據(jù)此優(yōu)化如下:
//玩家跳躍的行為 interface IJump { bool Jump(); } //玩家的基礎(chǔ)抽象類 abstract class Player { //玩家的級(jí)別 public int Level { get; set; } //其他屬性代碼省略一萬(wàn)字 } //真實(shí)玩家 class PersonPlayer : Player, IJump { public bool Jump() { if (Level >= 10) { return true; } return false; } }
不錯(cuò),到此我們已經(jīng)避免了初級(jí)人員所犯的錯(cuò)誤了,每種玩家類型可以根據(jù)需要自行去擴(kuò)展行為,改天產(chǎn)品狗在加一個(gè)10級(jí)玩家可以飛的行為,頂多在加一個(gè)IFly的行為接口,然后實(shí)現(xiàn)即可。但是這樣的設(shè)計(jì)就沒有問題了嗎?有,當(dāng)然有
每次需求其實(shí)還是改動(dòng)了已經(jīng)存在的并且穩(wěn)定運(yùn)行的老代碼,這是不可取的。而且修改老代碼,大大增加了bug出現(xiàn)的概率。
假如現(xiàn)在我們的游戲有20種玩家類型,其中19種需要添加跳躍的行為,那我們需要修改19個(gè)玩家的子類,工作量是如此之大。
利用類似繼承的方式擴(kuò)展對(duì)象的行為,是在編譯期就把對(duì)象的行為確定了。也就是說(shuō)在設(shè)計(jì)層面,其實(shí)你已經(jīng)把代碼寫死了。
有很多同學(xué)的代碼就到目前為止了
假設(shè)以下為產(chǎn)品狗一個(gè)月之后的新需求:
能跳躍的等級(jí)調(diào)整為11級(jí)
玩家添加能遁地的行為
新加了10種玩家類型
如果你讀到了這里,說(shuō)明大家都是對(duì)于設(shè)計(jì)追求卓越的技術(shù)人。這里菜菜再?gòu)?qiáng)調(diào)一遍架構(gòu)設(shè)計(jì)的一項(xiàng)重要原則
類應(yīng)該對(duì)修改關(guān)閉,對(duì)擴(kuò)展開放。
這里需要強(qiáng)調(diào)一點(diǎn),設(shè)計(jì)的每個(gè)部分想要都遵循開放-關(guān)閉原則,通常很難做到。因?yàn)橐朐诓恍薷默F(xiàn)有代碼的情況下,你需要花費(fèi)許多時(shí)間和精力。遵循開放關(guān)閉原則,通常需要引入更多的抽象,增加更多的層次,增大代碼的復(fù)雜度。因此菜菜建議把注意力集中在業(yè)務(wù)中最有可能變化的點(diǎn)上,這些地方應(yīng)用開放關(guān)閉原則。至于怎么確定哪些是變化的點(diǎn),這需要對(duì)業(yè)務(wù)領(lǐng)域很強(qiáng)的理解和經(jīng)驗(yàn)了。
現(xiàn)在我們分析一下我們要做的事情,我們希望一個(gè)對(duì)象(player)在不改動(dòng)的情況下動(dòng)態(tài)的給它賦予新的行為,在業(yè)務(wù)上實(shí)現(xiàn)的功能和用繼承的結(jié)果類似。總之一句話:
現(xiàn)有的類型優(yōu)雅的添加新行為,并且可以靈活疊加和替換
理想中的設(shè)計(jì)圖大致如下:
現(xiàn)在我們認(rèn)真分析一下,如果每個(gè)新的行為要想擴(kuò)展對(duì)象而又能保持該對(duì)象的自身特性,新行為對(duì)象必須是擴(kuò)展對(duì)象的子類,還必須包含對(duì)象的一個(gè)引用才能實(shí)現(xiàn)。
在系統(tǒng)設(shè)計(jì)過(guò)程中,實(shí)現(xiàn)一個(gè)接口泛指實(shí)現(xiàn)某個(gè)對(duì)象的超類型,也就是說(shuō)可以是類或者接口。
在你系統(tǒng)設(shè)計(jì)中,如果你的代碼依賴于某個(gè)具體的類型,并非抽象的超類型,應(yīng)用此篇介紹的設(shè)計(jì)方法可能會(huì)受到影響。
附加在對(duì)象最外層的行為,不應(yīng)該窺視被包裝的類型內(nèi)部的一些特性。
附加在對(duì)象外層的行為,可以在內(nèi)層對(duì)象的行為前后加入自己的行為,甚至可以覆蓋掉內(nèi)層對(duì)象的行為。
如果擴(kuò)展的行為過(guò)多,會(huì)出現(xiàn)很多小對(duì)象,過(guò)度使用會(huì)使程序變的很復(fù)雜,所以設(shè)計(jì)擴(kuò)展行為時(shí)候需要注意。
落實(shí)到代碼假設(shè)現(xiàn)在真實(shí)玩家的定義如下:
//玩家的基礎(chǔ)抽象類 public abstract class Player { //玩家的級(jí)別 public int Level { get; set; } //其他屬性代碼省略一萬(wàn)字 } //真實(shí)玩家 public class PersonPlayer : Player { }
現(xiàn)在的需求是給真實(shí)玩家添加一個(gè)10級(jí)能跳躍的行為,在不修改原有玩家代碼的情況下,擴(kuò)展跳躍行為代碼如下
//玩家行為的擴(kuò)展積累 public class PlayerExtension : Player { protected Player player; } //跳躍玩家的行為擴(kuò)展類 public class PlayerJumpExtension: PlayerExtension { public PlayerJumpExtension(Player _player) { player = _player; } public bool Jump() { if (player. Level >= 10) { return true; } return false; } }
測(cè)試代碼如下:
PersonPlayer player = new PersonPlayer(); //給用戶動(dòng)態(tài)添加跳躍的行為 PlayerJumpExtension jumpPlayer = new PlayerJumpExtension(player); var ret= jumpPlayer.Jump(); Console.WriteLine("玩家能不能跳躍:"+ret); //現(xiàn)在玩家升級(jí)到10級(jí)了 player.Level = 10; ret = jumpPlayer.Jump(); Console.WriteLine("玩家能不能跳躍:" + ret);
測(cè)試加過(guò)如下:
玩家能不能跳躍:False 玩家能不能跳躍:True
一個(gè)月后產(chǎn)品狗新加一個(gè)需求:真實(shí)玩家20級(jí)獲得飛行的行為,無(wú)序改動(dòng)現(xiàn)有代碼,只需繼續(xù)添加一個(gè)可以飛行的新擴(kuò)展
//玩家可以飛行的擴(kuò)展 public class PlayerFlyExtension : PlayerExtension { public PlayerFlyExtension(Player _player) { player = _player; } public bool Fly() { if (player.Level >= 20) { return true; } return false; } }
測(cè)試代碼如下:
PlayerFlyExtension flyPlayer = new PlayerFlyExtension(player); Console.WriteLine( "玩家能不能飛行"+flyPlayer.Fly()); player.Level = 20; Console.WriteLine("玩家能不能飛行" + flyPlayer.Fly());
測(cè)試結(jié)果:
玩家能不能飛行False 玩家能不能飛行True重要提示
以上代碼級(jí)別上屬于演示代碼,但是設(shè)計(jì)的理念卻很重要?;谝陨系脑O(shè)計(jì)思想,擴(kuò)展的行為完全有能力修改,覆蓋玩家的某些行為。比如玩家對(duì)象本身有一個(gè)喊話的行為,那擴(kuò)展類根據(jù)業(yè)務(wù)完全可以讓喊話行為執(zhí)行兩次等等修改。
添加關(guān)注,查看更精美版本,收獲更多精彩
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/74744.html
摘要:里氏替換原則里氏代換原則面向?qū)ο笤O(shè)計(jì)的基本原則之一。里氏代換原則中說(shuō),任何基類可以出現(xiàn)的地方,子類一定可以出現(xiàn)。里氏代換原則是對(duì)開閉原則的補(bǔ)充。而基類與子類的繼承關(guān)系就是抽象化的具體實(shí)現(xiàn),所以里氏代換原則是對(duì)實(shí)現(xiàn)抽象化的具體步驟的規(guī)范。 showImg(https://segmentfault.com/img/bVbuXAu?w=640&h=361); 本文為本次系列文章的第一篇,接下...
摘要:介紹超文本傳輸協(xié)議,是互聯(lián)網(wǎng)上應(yīng)用最為廣泛的一種網(wǎng)絡(luò)協(xié)議。年美國(guó)人構(gòu)思了一種通過(guò)計(jì)算機(jī)處理文本信息的方法,并稱之為超文本這成為了超文本傳輸協(xié)議標(biāo)準(zhǔn)架構(gòu)的發(fā)展根基。 Http介紹 超文本傳輸協(xié)議(HTTP,HyperText Transfer Protocol)是互聯(lián)網(wǎng)上應(yīng)用最為廣泛的一種網(wǎng)絡(luò)協(xié)議。所有的WWW文件都必須遵守這個(gè)標(biāo)準(zhǔn)。設(shè)計(jì)HTTP最初的目的是為了提供一種發(fā)布和接收HTML...
摘要:以及之前說(shuō)過(guò)的,當(dāng)程序員就是為了提高社會(huì)效率。寫高效的代碼是每個(gè)程序員的追求,寫易懂的代碼是每個(gè)程序員的美德。讓正確的程序更快,要比讓快速的程序正確容易得多。我覺得這樣才能當(dāng)一個(gè)有格局的程序員。 在博客閱讀:https://ssshooter.com/2019-04... 工作 寫程序不是為了炫耀自己的技術(shù),是要給公司創(chuàng)造價(jià)值,要確實(shí)幫助使用這個(gè)程序的人。以及之前說(shuō)過(guò)的,當(dāng)程序員就是為...
摘要:幸而,提供了造物主的接口這便是,或者稱為元類。接下來(lái)我們將通過(guò)一個(gè)栗子感受的黑魔法,不過(guò)在此之前,我們要先了解一個(gè)語(yǔ)法糖。此外,在一些小型的庫(kù)中,也有元類的身影。 首發(fā)于 我的博客 轉(zhuǎn)載請(qǐng)注明出處 接觸過(guò) Django 的同學(xué)都應(yīng)該十分熟悉它的 ORM 系統(tǒng)。對(duì)于 python 新手而言,這是一項(xiàng)幾乎可以被稱作黑科技的特性:只要你在models.py中隨便定義一個(gè)Model的子類,Dj...
閱讀 2710·2021-09-26 10:19
閱讀 2154·2021-09-24 10:27
閱讀 2534·2021-09-01 10:42
閱讀 2314·2019-08-29 16:09
閱讀 2494·2019-08-29 15:17
閱讀 1458·2019-08-29 15:09
閱讀 647·2019-08-29 11:14
閱讀 2314·2019-08-26 13:25