設計模式筆記(二)設計六大原則之二 黎克特制替換原則

2021-08-10 10:46:41 字數 3620 閱讀 8939

黎克特制替換原則

liskosubstitution principle lsp

只要父類出現的地方,子類就可以出現,而且替換為子類也不會有任何錯誤或異常,使用者可能根本不需要知道是父類還是子類。但是反過來就不行了,有子類出現的地方,父類未必能夠適應。

1.因為黎克特制替換要求,父類出現的地方子類一定能出現。所以在寫方法的時候如果用父類的引數,子類的功能可以根據需要傳入。這樣既得到了**的復用,又可以多功能的實現功能。

舉個栗子:

/*

* 父類:槍

* 有乙個抽象方法:殺敵

*/public

abstract

class abstractgun

/*

* 手槍的特點是攜帶方便,射程短

*/public

class

handgun

extends

abstractgun

}

/*

* 步槍的特點是射程遠,威力大

*/public

class

rifle

extends

abstractgun

}

/*

* 使用槍枝的士兵

*/public

class soldier

//士兵殺敵

public

void

killenemy()

}

/*

* 戰場場景測試

*/public

class client

}

士兵開始殺敵…

步槍射擊…

即使這個時候我們不想用步槍了,想要***,完全不用更改類設計得**,只需要在使用的時候給士兵步槍即可:

//三毛***殺敵

sanmao.setgun(new handgun());

sanmao.killenemy();

士兵開始殺敵…

手槍射擊…

在類中呼叫其他類時務必要使用父類或介面,如果不能使用父類或介面,說明類的設計已經違背了lsp原則。

2.如果子類不能完整地實現父類的方法,或者父類的某些方法在子類中已經發生「畸變」,則建議斷開父子繼承關係,採用依賴,聚集,組合等關係代替繼承。

舉個栗子:

這個時候我們又有了玩具槍,想一想,玩具槍也是槍啊,理所當然我們又繼承了abstractgun

/*

* 玩具槍

*/public

class

toygun

extends

abstractgun

}

這個時候如果三毛給的是玩具槍,哦哦

//三毛獲得了玩具槍

sanmao.setgun(new toygun());

sanmao.killenemy();

士兵開始殺敵…

玩具槍射擊…

發現並沒有達到該有的效果。

這個時候我們就需要重新設計一下類的關係。比如玩具槍的聲音和形狀模擬的槍枝,但是它並不屬於真槍的一種。

/*

* 我是玩具槍,不是射擊殺敵的真槍

*/public

abstract

class abstracttoygun ;

}

/*

* 父類:槍

* 有乙個抽象方法:殺敵

*/public

abstract

class abstractgun

/*

* 手槍的特點是攜帶方便,射程短

*/public

class

handgun

extends

abstractgun

@override

public

void

beauty()

}

/*

* 步槍的特點是射程遠,威力大

*/public

class

rifle

extends

abstractgun

//步槍

@override

public

void

beauty()

}

/*

* 手槍玩具槍

*/public

class

toygun2

extends

abstracttoygun

@override

public

void

shoot()

}

//我有乙個玩具槍,是乙個手槍樣式的

toygun2 toygun = new toygun2(new handgun());

toygun.beauty();

但是子類出現的地方,父類未必就可以勝任。也就是常說的向下轉型是不安全的。

因為加入父類的引數範圍比子類大,那麼很有可能呼叫時沒有實現正確的方法。

舉個栗子:

/*

* 之前說士兵可以有一把槍用來殺敵,士兵什麼槍都可以有,手槍和步槍

* 這裡假設乙個普通的小小兵,只可以拿手槍,當然他拿刀什麼的,這裡只關注槍的部分

*/public

class

generalperson

extends

soldier

}

/*

* 使用槍枝的士兵

*/public

class soldier

}

//產生三毛這個士兵

soldier sanmao = new soldier();

//手槍殺敵

sanmao.killenemy(new handgun());

//產生四毛這個小兵

generalperson simao = new generalperson();

//手槍殺敵

simao.killenemy(new handgun());

士兵開始殺敵…

手槍射擊…

小兵開始殺敵…

手槍射擊…

我們發現執行了子類的方法,明明我們希望所有的士兵不管用什麼槍枝殺敵都用士兵這個方法,但是子類由於引數範圍比父類的小,導致這個時候扭曲了父類的意圖,達到了不一樣的功能。

意思是說,父類的乙個方法返回值是乙個型別t,子類的相同方法(重寫或覆寫)的返回值是s,那麼黎克特制替換原則要求s必須小於等於t。也就是說要麼s和t是同乙個型別,要麼s是t的子類。

覆寫的時候,父類和子類的同名方法的輸入引數是相同的,兩個方法的返回值s小於等於t。這是覆寫的要求所在。

過載的話,則要求輸入引數型別或數量不同,黎克特制替換中要求,子類的輸入引數寬於或等於父類的輸入引數,也就是說這個方法時不會被呼叫的。

C 設計模式之二(設計模式六大原則)

精彩部落格 補充一下面對物件設計八大原則 前五大原則與設計模式的前五大原則相同,為 1 單一職責原則 single responsibility principle,srp 乙個類只負責乙個功能領域中的相應職責,或者可以定義為 就乙個類而言,應該只有乙個引起它變化的原因。2 開閉原則 open cl...

設計模式六大原則

0.05 設計模式 設計模式 規範 筆記 大話設計模式 物件導向的關鍵在於封裝,封裝好了才能很好的復用,達到單一職責和開放擴充套件 封閉更改的效果。1 單一職責原則 就乙個類而言,應該僅有乙個引起它變化的原因.增加功能不應該修改已有的 避免修改出錯及重複測試.如果你能夠想到多於乙個的動機去改變乙個類...

設計模式六大原則

0.05 設計模式 設計模式 規範 筆記 大話設計模式 物件導向的關鍵在於封裝,封裝好了才能很好的復用,達到單一職責和開放擴充套件 封閉更改的效果。1 單一職責原則 就乙個類而言,應該僅有乙個引起它變化的原因.增加功能不應該修改已有的 避免修改出錯及重複測試.如果你能夠想到多於乙個的動機去改變乙個類...