对LSP的理解,之前只停留在表面,并未深入理解。表面理解是指认为LSP就是仅仅依靠面向对象多态的特性,在使用基类对象的地方都能使用子类对象简单的替换。这还不是严格的遵循LSP。真正的要遵循LSP原则,是必须子类和基类行为上的绝对一致。基于契约的设计可以很好的保证了对LSP的遵循。
从测试代码 testLspViolate看出,当用派生类对象替换基类对象时,发生AssertError 说明违反了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 {
@Override
public void lspViolate(String s1, String s2) {
assert s1 != null;
super.lspViolate(s1, s2);
}
@Override
public 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
*/
@Test
public void testLspViolate() {
Client client = new Client();
Base base = new Base();
Base derived = new Derived();
client.lspViolate(base);
// 当用派生类对象替换基类对象时,发生AssertError 说明违反了LSP原则,因为派生类的方法前置条件比基类更加严格了
client.lspViolate(derived);
}
/**
* 测试遵循LSP
*/
@Test
public void testLspFollow() {
Client client = new Client();
Base base = new Base();
Base derived = new Derived();
client.lspFollow(base);
client.lspFollow(derived);
}
}
从测试代码 testLspViolate看出,当用派生类对象替换基类对象时,发生AssertError 说明违反了LSP原则,因为派生类的方法前置条件比基类更加严格了。
参考:基于契约的设计