設計模式-里氏替換原則
優點
面向對象的語言繼承必不可少的,有如下優點
- 代碼共享,減少創建類的工作量
- 提高代碼的重用性
- 提高代碼的可擴展性
- 提高代碼的可擴展性
- 提高產品代碼的開放性
- 繼承侵入性 只要繼承,必須擁有父類的內容
- 降低代碼的靈活性,子類必須擁有父類的屬性和方法
- 增強耦合性。
提供規範
里氏替換原則,爲繼承定義規範。
長方形是不是正方形
正方形是一種特殊的長方形,如果將正方形設計爲長方形的子類,不符合里氏替換原則
下方有三個類
類圖如下
關係如上所示
package demo1; public class SmartTest { /* * 長方形的長增加超過寬 * * @param r * */ public void resize(Rectangle r) { while (r.getHeight() <= r.getWidth()) { r.setHeight(r.getHeight() + 1); } } }
package demo1; /* * 定義一個長方形類 * @author ming * */ public class Rectangle { protected long width; // 可以訪問基類繼承而來的,不能訪問基類本身的,對同包內的可見,並且子類也可見 protected long height; public void setWidth(long width) { this.width = width; } public long getWidth() { return this.width; } public void setHeight(long height) { this.height = height; } public long getHeight() { return this.height; } }
package demo1; /* * 定義一個正方形類繼承自長方形類 * * @author ming * * */ public class Square extends Rectangle{ public void setWidth(long width, long height) { this.width = width; this.height = height; } public long getWidth() { return width; } public void setHeight(long height, long width) { this.height = height; this.width = width; } public long getHeight() { return height; } }
在上面的三塊代碼中,當調用SmartTest類的resize方法的時候,如果傳入的是父類,那麼將會可以的,如果傳入的是子類,正方形,那麼將會不可以的。
即。上方的爲長方形行,正方形不行。
所以上面的栗子不符合里氏替換原則。
解決方法,使用繼承時,要遵守里氏替換原則,類B繼承類A時,不要重寫父類A的方法,也不能重載父類A的方法。
如果代碼更改如下更改
讓其兩個都共同定義同一個父類即可
其中最上層的類爲兩個類的抽象類。
改進如下
package com.ming; /* * 定義一個四邊形類,只有get方法set方法 * @author ming * */ public abstract class Quadrangle { protected abstract long getWidth(); protected abstract long getHeight(); }
package com.ming; public class Rectangle extends Quadrangle { private long width; private long height; public void setWidth(long width) { this.width = width; } public long getWidth() { return this.width; } public void setHeight(long height) { this.height = height; } public long getHeight() { return this.height; } }
package com.ming; public class Square extends Quadrangle{ private long width; private long height; public void setWidth(long width) { this.height = width; this.width = width; } public long getWidth() { return this.,width; } public void setHeight(long height) { this.height = height; this.width = height; } public long getHeight() { return this.height; } }
在上方的圖中,由於兩個爲平級關係,所以父類的地方,換成子類也都可以。
總結
里氏替換原則;父類可以的地方,換成子類也同樣可以。
爲什麼要符合
一個栗子
package com.ming2; public class A { public int func1(int a, int b) { return a-b; } }
package com.ming2; public class B extends A{ public int func1(int a, int b) { return a+b; } public int func2(int a, int b) { return func1(a,b)+100; // 調用func1 } }
在上方中,如果這樣書寫
package com.ming2; public class Client { public static void main(String[] args) { B b = new B(); System.out.println(b.func1(100, 50)); } }
就違反了里氏替換原則,即子類能使用的時候,父類也必須能使用。
www.iming.info