您好,登錄后才能下訂單哦!
C#forUnity編程語言快速入門教程(連載10)_C#OOP編程之里氏替換原則
最近在Unity教學(xué)過程中,有學(xué)員對于C#的“里氏替換原則”(LSP)產(chǎn)生疑問表示不太理解。問題集中在不知道這個(gè)原則是做什么,有什么優(yōu)勢,具體在游戲開發(fā)(程序開發(fā))過程中有什么借鑒與指導(dǎo)作用。
就以上問題我總結(jié)梳理一下,與大家共同探討。
起源: 在我們的程序開發(fā)過程中,起初應(yīng)該都是以完成項(xiàng)目功能為重點(diǎn)。但是隨著軟件規(guī)模的不斷擴(kuò)大,人們發(fā)現(xiàn)只完成功能是遠(yuǎn)遠(yuǎn)不夠的。于是聰明的軟件工程師,從大量的編程實(shí)踐中開始總結(jié)一些共性的軟件開發(fā)理論,以供后人規(guī)范編程,更有效率、更穩(wěn)定的開發(fā)各種項(xiàng)目(包括游戲項(xiàng)目)。
目前公認(rèn)的一些編程原則:
1: 單一職責(zé)原則 英文名稱是Single Responsibility Principle,簡稱SRP
2: 開閉原則 英文全稱是Open Close Principle,簡稱OCP
3: 里氏替換原則 英文全稱是Liskov Substitution Principle,簡稱LSP
4: 依賴倒置原則 英文全稱是Dependence Inversion Principle,簡稱DIP
在以上編程開發(fā)原則中,“開閉原則”與“里氏替換原則”比較類似,都是研究如何在相對穩(wěn)定的編碼環(huán)境中,盡可能的允許程序功能的變化。也就是最低的編碼改動量,實(shí)現(xiàn)最大程度的軟件項(xiàng)目變化性,來適應(yīng)用戶對軟件系統(tǒng)不斷變化的功能要求。
解釋如上概念:
“開放-封閉原則”(即: 開閉原則)(OCP): 對于程序的擴(kuò)展是開放的(Open for extension),對于程序的修改是封閉的(Closed for modification)
“里氏替換原則”:子類型必須能夠替換掉它們的父類型?。ǚ粗畡t不成立)
“ 里氏替換”(也叫“里氏代換”原則)原則英文全稱是Liskov Substitution Principle,簡稱LSP。 由2008年圖靈獎得主、美國第一位計(jì)算機(jī)科學(xué)女博士Barbara Liskov教授和卡內(nèi)基·梅隆大學(xué)Jeannette Wing教授于1994年提出。 里氏替換原則就是要求寫程序前,先建立抽象,通過抽象建立規(guī)范,具體的實(shí)現(xiàn)在運(yùn)行時(shí)替換掉抽象,保證系統(tǒng)的高擴(kuò)展性、靈活性。
“開閉原則”要求我們寫的程序修改盡量要少(即:封閉),但是對于功能的擴(kuò)展確實(shí)開放的、允許的。 這其實(shí)是提了一個(gè)很高的編程目標(biāo),很好的一個(gè)指導(dǎo)原則,但是如何具體到實(shí)現(xiàn)上,是沒有方法的,是不接“底氣”的。 所以“里氏替換”就給了一個(gè)具體的實(shí)現(xiàn)方法的原則,就是讓子類來無縫的對接父類,“子類型必須能夠替掉父類”。
“里氏替換原則”具體的要求可以表述如下:
1: 子類的所有方法必須在父類中聲明,或子類必須實(shí)現(xiàn)父類中聲明的所有方法。根據(jù)里氏替換原則,為了保證系統(tǒng)的擴(kuò)展性,在程序中通常使用父類來進(jìn)行定義,如果一個(gè)方法只存在子類中,在父類中不提供相應(yīng)的聲明,則無法在以父類定義的對象中使用該方法。
2: 我們在運(yùn)用里氏替換原則時(shí),盡量把父類設(shè)計(jì)為抽象類或者接口,讓子類繼承父類或?qū)崿F(xiàn)父接口,并實(shí)現(xiàn)在父類中聲明的方法,運(yùn)行時(shí),子類實(shí)例替換父類實(shí)例,我們可以很方便地?cái)U(kuò)展系統(tǒng)的功能,同時(shí)無須修改原有子類的代碼,增加新的功能可以通過增加一個(gè)新的子類來實(shí)現(xiàn)。里氏替換原則其實(shí)就是“開閉原則”的具體實(shí)現(xiàn)手段之一!
我們從序號為2的表述中可以看出,其實(shí)“里氏替換”原則就是一種更加具體的手段來實(shí)現(xiàn)“開閉原則”。 序號為2的理論其實(shí)就是我們常說的“動態(tài)多態(tài)性”的規(guī)則。
針對以上理論,為了更好的理解,筆者給出“里氏替換原則”的實(shí)現(xiàn)參考代碼,供C#初學(xué)者進(jìn)行參考研究,有具體問題,可以留言,謝謝!
//參考源碼1: 以下是使用“虛方法”,來實(shí)現(xiàn)“里氏替換”。
class Person
{
//虛方法
public virtual void SpeakLanguage()
{
Console.WriteLine("Person, 說話方法");
}
}
class MrLiu:Person
{
//方法重寫
public override void SpeakLanguage()
{
Console.WriteLine("MrLiu, 劉老師說中國話!");
}
}
class Tom:Person
{
//方法重寫
public override void SpeakLanguage()
{
Console.WriteLine("Tom, Tom Speak Engligh!");
}
}
class Test
{
public static void Main()
{
/* “里氏替換原則”(即:動態(tài)多態(tài)性)測試 */
//功能的定義部分
//Person per = new MrLiu(); //打印“MrLiu, 劉老師說中國話!”
Person per = new Tom(); //打印“Tom, Tom Speak Engligh!”
//功能的實(shí)現(xiàn)部分
per.SpeakLanguage();
}
}
//參考源碼2: 以下是使用“接口”,來實(shí)現(xiàn)“里氏替換”。
interface ISpeakable
{
//抽象方法
void SpeakLanguage();
}
class MrLiu:ISpeakable
{
//方法實(shí)現(xiàn)
void ISpeakable.SpeakLanguage()
{
Console.WriteLine("MrLiu, 劉老師說中國話!");
}
}
class Tom:ISpeakable
{
//方法實(shí)現(xiàn)
void ISpeakable.SpeakLanguage()
{
Console.WriteLine("Tom, Tom Speak Engligh!");
}
}
class Test
{
public static void Main()
{
/* “里氏替換原則”(即:動態(tài)多態(tài)性)測試 */
//功能的定義部分
//ISpeakable Ispeak = new Tom();//打印“Tom, Tom Speak Engligh!”
ISpeakable Ispeak = new MrLiu();//打印“MrLiu, 劉老師說中國話!”
//功能的實(shí)現(xiàn)部分
Ispeak.SpeakLanguage();
}
}
以上兩段代碼,分別用了父類“虛方法”與“接口”的方式分別實(shí)現(xiàn)“里氏替換”,當(dāng)然還可以用“抽象類”來實(shí)現(xiàn),究竟三者哪個(gè)方式,更應(yīng)該優(yōu)先使用呢? 現(xiàn)給出一個(gè)原則:
“里氏替換”原則可以用以下方式來實(shí)現(xiàn):
1> 虛方法的動態(tài)多態(tài)性。
2> 抽象方法的動態(tài)多態(tài)性。
3> 接口方法的動態(tài)多態(tài)性。
規(guī)則: 實(shí)現(xiàn)“里氏替換”原則(動態(tài)多態(tài)性): 能用接口,不用抽象方法,能用抽象方法,不用虛方法。
好了,針對以上問題,筆者就總結(jié)以上內(nèi)容,感興趣的C#編程愛好者可以進(jìn)行留言討論。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。