對LSP的理解,之前只停留在表面,並未深入理解。表面理解是指認為LSP就是僅僅依靠物件導向多態的特性,在使用基類對象的地方都能使用子類對象簡單的替換。這還不是嚴格的遵循LSP。真正的要遵循LSP原則,是必須子類和基類行為上的絕對一致。基於契約的設計可以很好的保證了對LSP的遵循。
下面簡單的java代碼,揭示了LSP真諦:
package com.oop.lsp;public class Base {public void lspViolate(String s1, String s2) {}public void lspFollow(String s1, String s2) {assert s1 != null;}}////////////////package com.oop.lsp;public class Derived extends Base {@Overridepublic void lspViolate(String s1, String s2) {assert s1 != null;super.lspViolate(s1, s2);}@Overridepublic void lspFollow(String s1, String s2) {super.lspFollow(s1, s2);}}///////////////package com.oop.lsp;public class Client {public void lspViolate(Base obj) {obj.lspViolate(null, null);}public void lspFollow(Base obj) {obj.lspFollow("", null);}}/////////////
package com.oop.lsp;import org.junit.Test;public class LspTest {/** * 測試違反LSP */@Testpublic void testLspViolate() {Client client = new Client();Base base = new Base();Base derived = new Derived();client.lspViolate(base);// 當用衍生類別對象替換基類對象時,發生AssertError 說明違反了LSP原則,因為衍生類別的方法前置條件比基類更加嚴格了client.lspViolate(derived);}/** * 測試遵循LSP */@Testpublic void testLspFollow() {Client client = new Client();Base base = new Base();Base derived = new Derived();client.lspFollow(base);client.lspFollow(derived);}}
從測試代碼 testLspViolate看出,當用衍生類別對象替換基類對象時,發生AssertError 說明違反了LSP原則,因為衍生類別的方法前置條件比基類更加嚴格了。
參考:基於契約的設計