里氏代换原则
里氏代换原则是面向对象设计的基本原则之一
里氏代换原则: 任何基类可以出现的地方,子类一定可以出现。通俗理解:子类可以扩展父类的功能,但不能改变父类原有的功能。换句话说,子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。 如果通过重写父类的方法来完成新的功能,这样写起来虽然简单,但是整个继承体系的可复用性会比较差,特别是运用多态比较频繁时,程序运行出错的概率会非常大。 下面看一个里氏替换原则中经典的一个例子 【例】正方形不是长方形. 在数学领域里,正方形毫无疑问是长方形,它是一个长宽相等的长方形。所以,我们开发的一个与几何图形相关的软件系统,就可以顺理成章的让正方形继承自长方形。
//长方形类
class Rectangle{
var length:Double
var width:Double
init(length:Double,width:Double){
self.length = length
self.width = width
}
}
//正方形类 继承自长方形
class Square:Rectangle{
override var length: Double{
set{
super.width = newValue
super.length = newValue
}
get {
return super.length
}
}
override var width: Double{
set {
super.width = newValue
super.length = newValue
}
get {
return super.width
}
}
}
测试
// 扩宽方法
func resize(rectangle:Rectangle){
// 如果宽比长小,进行扩宽的操作
while(rectangle.width <= rectangle.length){
print(rectangle.width)
rectangle.width += 1
}
}
func printWidthAndLength(rectangle:Rectangle){
print("长:",rectangle.length,"\n宽:",rectangle.width)
}
//创建长方形对象
var rectangle:Rectangle = Rectangle(length: 20, width: 10)
resize(rectangle: rectangle)
printWidthAndLength(rectangle: rectangle)
print("====================================")
//创建正方形对象
var square = Square(length: 20, width: 20)
resize(rectangle: square)
printWidthAndLength(rectangle: square)

正方形继承自长方形,根据里氏替换原则,正方形可以出现在长方形出现的位置,然而正方形调用扩宽方法的时候。陷入了死循环,直到 系统产生溢出错误。所以该代码违背了里氏替换原则,他们之间的继承关系不成立,正方形不是长方形。那么如何改进呢?我们需要重新设计他们之间的关系,定义一个四边形的接口,让长方形和正方形继承自该接口,同时实现接口定义的方法。
//四边形接口
protocol Quadrilateral{
func getWidth()->Double
func getLength()->Double
}
//正方形类
class Square:Quadrilateral{
var side:Double = 0
init(side:Double) {
self.side = side
}
func getWidth() -> Double {
return side
}
func getLength() -> Double {
return side
}
}
//长方形类
class Rectangle:Quadrilateral{
var width:Double = 0
var length:Double = 0
init(width:Double,length:Double) {
self.width = width
self.length = length
}
func getWidth() -> Double {
return self.width
}
func getLength() -> Double {
return self.length
}
}
// 扩宽方法
func resize(rectangle:Rectangle){
// 如果宽比长小,进行扩宽的操作
while(rectangle.width <= rectangle.length){
print(rectangle.width)
rectangle.width += 1
}
}
func printWidthAndLength(quadrilateral:Quadrilateral){
print("长:",quadrilateral.getLength(),"\n宽:",quadrilateral.getWidth())
}
//创建长方形对象
var rectangle:Rectangle = Rectangle(width: 10, length: 20)
resize(rectangle: rectangle)
printWidthAndLength(quadrilateral: rectangle)
此时正方形跟长方形没有继承关系,正方形不能调用扩宽方法,符合里氏代换原则.
感谢黑马程序员课程