亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

設計模式六大原則(2)--里氏替換原則

2019-11-17 03:01:13
字體:
來源:轉載
供稿:網友
設計模式六大原則(2)--里氏替換原則

定義:

程序中的對象應該是可以在不改變程序正確性的前提下被它的子類所替換,也就是說所有引用基類的地方必須能透明地使用其子類的對象。通俗的來說,子類可以擴展父類的功能,但不能改變父類原有的功能。

由來:

第一次看見這個里氏替換原則的名字會覺著很奇特,根據以往的經驗這一看就是外國友人首先提出的概念,然后便以她的姓命名該原則。確實是這樣,它由芭芭拉·利斯科夫(Barbara Liskov)在1987年在一次會議上名為“數據的抽象與層次”的演說中首先提出。里氏替換原則英文名稱為Liskov Substitution PRinciple,所以簡稱為LSP。

深入:

里氏替換原則為良好的繼承定義了一個規范,一句簡單的定義包含了四層含義:

  • 子類必須完全實現父類的方法

我們在做系統設計時經常編寫接口和抽象類,然后編碼繼承它們,其實這里已經應用了里氏替換原則。比如,我們簡單實現一下CS中的各種槍(定義抽象類,然后繼承),槍的類圖如下所示:

image

槍的主要職責是殺人,每種槍都有自己的特點。shou槍是單發且射程較近,步槍射程遠威力大,機槍主要用于掃射。同時定義一個士兵類,KillEnemy(AbstractGun gun)方法使用槍來殺人,具體使用什么槍調用時才會知道。

槍抽象類、常用槍和士兵類代碼實現如下所示:

/// <summary>    /// 槍抽象類    /// </summary>    public abstract class AbstractGun    {        public abstract void Shoot();    }    /// <summary>    /// shou槍    /// </summary>    public class HandGun : AbstractGun    {        public override void Shoot()        {            Console.WriteLine("shou槍射擊...");        }    }    /// <summary>    /// 步槍    /// </summary>    public class Rifle : AbstractGun    {        public override void Shoot()        {            Console.WriteLine("步槍射擊...");        }    }    /// <summary>    /// 機槍    /// </summary>    public class MachineGun : AbstractGun    {        public override void Shoot()        {            Console.WriteLine("機槍射擊...");        }    }    /// <summary>    /// 士兵類    /// </summary>    public class Solder    {        public void KillEnemy(AbstractGun gun)        {            Console.WriteLine("士兵開始殺人...");            gun.Shoot();        }    }

場景類(主函數)代碼如下所示:

class Client    {        static void Main(string[] args)        {            var solder = new Solder();            solder.KillEnemy(new Rifle());            Console.ReadKey();        }     }

運行結果如下所示:

image

在這個程序中,我們給三毛這個士兵一把步槍,然后就開始殺敵了,如果三毛要使用機槍當然也可以,直接把solder.killEnemy(new Rifle())修改為 solder.killEnemy(new MachineGun())就可以了,在編寫程序時Solider士兵類根本就不用知道是哪個型號的槍(子類)被傳入。

注意在類中調用其他類時務必要使用父類或接口,如果不能使用父類或接口,則說明類的設計已經違背了LSP原則。

如果現在我們想嫁個玩具槍,那我們就加一個TonyGun類繼承AbstractGun,加入玩具槍后新的類圖如下所示:

image

但是考慮到實際情況,因為玩具槍一般是殺不死人的,所以玩具槍里的類是不能實現殺人的,如下代碼所示只能把該方法置空:

/// <summary>    /// 玩具槍    /// </summary>    public class TonyGun : AbstractGun    {        public override void Shoot()        {            //玩具槍不能射擊,這里就不能實現了        }    }

把槍改為玩具槍,演示代碼如下所示:

class Client    {        static void Main(string[] args)        {            var solder = new Solder();            solder.KillEnemy(new TonyGun());            Console.ReadKey();        }     }

運行結果如下:

image

結果只提示士兵殺人卻沒有發射子彈(因為用的是玩具槍,有點搞)。

在這種情況下,我們發現業務調用類已經出現了問題,正常的業務邏輯已經不能運行,那怎么辦?好辦,有兩種解決辦法:

1.在Soldier類中增加instanceof的判斷,如果是玩具槍,就不用來殺敵人。這個方法可以解決問題,但是你要知道,在程序中,每增加一個類,所有與這個父類有關系的類都必須修改,你覺得可行嗎?如果你的產品出現了這個問題,因為修正了這樣一個Bug,就要求所有與這個父類有關系的類都增加一個判斷,客戶非跳起來跟你干架不可!你還想要你的客戶忠誠你嗎?顯然,這個方案被否定了。

2.ToyGun脫離繼承,建立一個獨立的父類,為了做到代碼可以復用,可以與AbastractGun建立關聯委托關系

注意:如果子類不能完整地實現父類的方法,或者父類的某些方法在子類中已經發生“畸變”,則建議斷開父子繼承關系,采用依賴、聚集、組合等關系代替繼承。

  • 子類可以有自己的個性

子類當然可以有自己的行為和外觀(也就是方法和屬性),這里為什么要提呢?因為里氏替換原則是不能到這使用的的,子類可以替換父類,但是父類不能替換父類(如果能替換也就沒必要派生子類了),具體就不解釋了(定義就是這么定義的,道理比較淺顯),用下面的圖做一下簡單的說明:

image

  • 覆蓋或實現父類的方法時輸入參數可以被放大

方法中的輸入參數稱為前置條件,這是什么意思呢?大家做過Web Service開發就應該知道有一個“契約優先”的原則,也就是先定義出WSDL接口,制定好雙方的開發協議,然后再各自實現。里氏替換原則也要求制定一個契約,就是父類或接口,這種設計方法也叫做Design by Contract,契約設計,是與里氏替換原則融合在一起的。契約制定了,也就同時制定了前置條件和后置條件,前置條件就是你要讓我執行,就必須滿足我的條件;后置條件就是我執行完了需要反饋,標準是什么。

子類在沒有覆寫父類的方法的前提下,子類方法被執行了,這會引起業務邏輯混亂,因為在實際應用中父類一般都是抽象類,子類是實現類,你傳遞一個這樣的實現類就會“歪曲”了父類的意圖,引起一堆意想不到的業務邏輯混亂,所以子類中方法的前置條件必須與超類中被覆蓋的方法的前置條件相同或者更寬松

  • 覆蓋或實現父類的方法時輸出結果可以被縮小

這是什么意思呢,父類的一個方法的返回值是一個類型T,子類的相同方法(重載或覆寫)的返回值為S,那么里氏替換原則就要求S必須小于等于T,也就是說要么S和T是同一個類型,要么S是T的子類,為什么呢?分兩種情況,如果是覆寫,父類和子類的同名方法的輸入參數是相同的,兩個方法的范圍值S小于等于T,這是覆寫的要求,這才是重中之重,子類覆寫父類的方法,天經地義。如果是重載,則要求方法的輸入參數類型或數量不相同,在里氏替換原則要求下,就是子類的輸入參數大于或等于父類的輸入參數,也就是說你寫的這個方法是不會被調用到的,參考上面講的前置條件。采用里氏替換原則的目的就是增強程序的健壯性,版本升級時也可以保持非常好的兼容性。即使增加子類,原有的子類還可以繼續運行。在實際項目中,每個子類對應不同的業務含義,使用父類作為參數,傳遞不同的子類完成不同的業務邏輯,非常完美!

總結:

看上去很不可思議,因為我們會發現在自己編程中常常會違反里氏替換原則,程序照樣跑的好好的。所以大家都會產生這樣的疑問,假如我非要不遵循里氏替換原則會有什么后果? 后果就是:你寫的代碼出問題的幾率將會大大增加。

PS:最后提交時竟然提示[手.槍]是違禁詞,只好改成了shou槍


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩精品中文字幕在线观看| 亚洲欧美日韩国产中文| 久久这里只有精品99| 91人成网站www| 国产黑人绿帽在线第一区| www.国产精品一二区| 欧美日韩第一页| 国产在线高清精品| 久久久噜噜噜久久中文字免| 精品久久久久久久久久ntr影视| 黄色一区二区三区| 亚洲影院高清在线| 97国产在线观看| 亚洲美女免费精品视频在线观看| 欧美成人免费大片| 成人黄色短视频在线观看| 国模视频一区二区三区| 欧美大码xxxx| 久久91亚洲精品中文字幕奶水| 欧美亚洲一级片| 亚洲aⅴ日韩av电影在线观看| 日韩精品欧美国产精品忘忧草| 日韩精品福利在线| 久久久伊人欧美| 国产91在线高潮白浆在线观看| 日韩一区av在线| 国产女人18毛片水18精品| 日韩av免费网站| 青青精品视频播放| 日韩欧美在线免费| 中文字幕精品一区二区精品| 欧美激情国产高清| 精品亚洲一区二区三区四区五区| 成人h视频在线| 精品五月天久久| 国产日韩欧美在线播放| 91精品国产成人| 亚洲美女性生活视频| 午夜精品www| 亚州国产精品久久久| 国产成人精品午夜| 国产精品久久久久久av福利| 亚洲xxxx视频| 狠狠色香婷婷久久亚洲精品| 久久中文字幕在线| 亚洲一区二区国产| 国产精品爽爽ⅴa在线观看| 欧美激情精品久久久久久久变态| 欧美激情久久久| 色综合久久久久久中文网| 亚洲在线观看视频| 亚洲国产高潮在线观看| 欧美刺激性大交免费视频| 日韩免费在线电影| 亚洲成人三级在线| 日韩av在线播放资源| 午夜精品久久久久久久久久久久| 国产精品99久久久久久久久久久久| 国产精品影院在线观看| 97久久精品人人澡人人爽缅北| 亚洲精品免费网站| 91九色国产在线| 欧美猛男性生活免费| 色偷偷亚洲男人天堂| 亚洲图片欧洲图片av| 久久久久九九九九| 精品动漫一区二区| 91久久久久久久久| 国产97在线观看| 久热爱精品视频线路一| 国产日韩在线视频| 国产一区私人高清影院| 97国产在线视频| 亚洲美腿欧美激情另类| 亚洲香蕉成人av网站在线观看| 中文字幕欧美专区| 日韩精品在线观看一区二区| 国产精品av网站| 欧美丝袜一区二区| 亚洲一区二区三区sesese| 18性欧美xxxⅹ性满足| 成人日韩在线电影| 97香蕉久久夜色精品国产| 亚洲成人精品视频| 在线观看日韩视频| 久久精品影视伊人网| 91精品国产高清自在线看超| 亚洲欧美国产另类| 亚洲成在人线av| 国产精品视频最多的网站| 这里只有精品丝袜| 国产精品69久久久久| 夜夜狂射影院欧美极品| 国语自产偷拍精品视频偷| 欧美www在线| 91精品国产91久久久| 九九精品在线视频| 日韩专区中文字幕| 国产日韩在线精品av| 欧美体内谢she精2性欧美| 国产精品久久久久久久久久久不卡| 亚洲欧美在线第一页| 国产在线观看精品一区二区三区| 亚洲精品永久免费| 伊人一区二区三区久久精品| 777午夜精品福利在线观看| 日韩精品在线视频| 国产91在线高潮白浆在线观看| 欧美黄色成人网| 亚洲成人1234| 懂色aⅴ精品一区二区三区蜜月| 亚洲aaaaaa| 久久夜色精品国产亚洲aⅴ| 日韩欧美一区二区三区| 亚洲va男人天堂| 午夜精品一区二区三区视频免费看| 国产精品电影一区| 亚洲精品99久久久久中文字幕| 亚洲国产成人91精品| 国产精品99免视看9| 91精品久久久久久久久不口人| 欧美另类老女人| 97久久精品人人澡人人爽缅北| 伊人激情综合网| 国产精品一区专区欧美日韩| 欧美精品福利在线| 国产主播喷水一区二区| 97成人精品视频在线观看| 欧美视频中文字幕在线| 午夜伦理精品一区| 国产69精品久久久久99| 国产精品久久久久久久天堂| 欧美疯狂性受xxxxx另类| 国产精品爽黄69| 91成品人片a无限观看| 亚洲乱码av中文一区二区| 黑人巨大精品欧美一区免费视频| 久久天堂av综合合色| 青青青国产精品一区二区| 日韩免费av一区二区| 欧美性xxxxxxx| 国产精品免费网站| 日韩精品久久久久久福利| 78m国产成人精品视频| 亚洲精品视频久久| 国产日韩欧美中文在线播放| 亚洲精品理论电影| 97视频在线观看成人| 中文字幕亚洲欧美一区二区三区| 欧美精品免费在线| 亚洲最大在线视频| 国产一区二区在线免费视频| 在线成人中文字幕| 欧美激情视频三区| 成人黄色av播放免费| www.国产一区| 伊人亚洲福利一区二区三区| 亚洲精品国产精品国产自| x99av成人免费| 午夜精品久久久久久久久久久久| 欧美做受高潮1| 欧美激情欧美激情在线五月| 欧美激情二区三区| 色先锋资源久久综合5566|