Java设计模式之里氏替换原则(Liskov Substitution principle)

    Java是面向对象的语言,那么什么是面向对象程序设计呢?

面向对象程序设计(英语:Object-oriented programming,缩写:OOP),将具体的事物抽象化。在Java中的表现就是将客观存在的事物(哺乳动物,音乐,美酒)封装成抽象的类(class),类包含事物的属性、行为等。不同的事物(class)之间通过消息传递。对象就是类(class)的实例(具体存在的事物个体),讲数据和程序封装起来,提高软件的灵活性、复用性、扩展性等。

    那么什么是里氏替换原则(LSP)呢?

Barbara Liskov 和 Jeannette Wing 在1994年的原文中是这么定义的:

Subtype Requirement: Let 05214816_TZRj.jpg be a property provable about objects 05214817_1U58.jpg of type T. Then 05214817_9tyi.jpg 

should be true for objects  05214817_Qtgc.jpg of type S where S is a subtype of T.

    原谅我蹩脚的英文,我个人理解意思就是:对于类型T的属性x可以推导出f(x),如果S是T的子类型,并且对于类型S的属性y有f(y)成立。

    再引申一点讲就是:如果对于每一个类型为T的对象m,都有类型为S的对象n,满足以T定义的所以程序将对象m替换成n的时候,程序的行为没有改变,即T是S的父类,且子类可以替换父类。看上去好像挺好理解的,好像子类继承自父类,那么为什么不能替换呢,又不会报ClassCastException。然而(but),看官请往下看......

    我们照例拿代码来举个反例例子(下面是我从网上找到的比较经典的例子):

矩形(Rectangle):

/**
 * 矩形有两个属性,长(length)和宽(breadth)
 */
public class Rectangle {
    private int length;
    private int breadth;

    public int getLength() {
        return length;
    }

    public void setLength(int length) {
        this.length = length;
    }

    public int getBreadth() {
        return breadth;
    }

    public void setBreadth(int breadth) {
        this.breadth = breadth;
    }

    public int getArea() {
        return this.length * this.breadth;
    }
}

长方形(Square):


/**
 * 长方形,长方形本来只有边长,但是为了便于理解我们直接Override了父类的方法
 */
class Square extends Rectangle {
    @Override
    public void setBreadth(int breadth) {
        super.setLength(breadth);
        super.setBreadth(breadth);
    }
    @Override
    public void setLength(int length) {
        super.setLength(length);
        super.setBreadth(length);
    }
}

那么我们来做个小测试:


public class LspTest
{
    private static Rectangle getNewRectangle()
    {
        // it can be an object returned by some factory ...
        // 返回Square实例
        return new Square();
    }

    public static void main (String args[])
    {
        Rectangle r = LspTest.getNewRectangle();

        r.setBreadth(5);
        r.setLength(10);
        // user knows that r it's a rectangle.
        // 用户知道r是一个Rectangle类的实例
        // It assumes that he's able to set the width and length as for the base class
        // r实例可以设置width和length

        System.out.println((r.getClass().getName()));
        System.out.println(r.getArea());
        // now he's surprised to see that the area is 100 instead of 50.
        // 输出结果让人惊讶,本来觉得应该是Rectangle和50,但是却是Rectangle和100,
        // 所以这种情况不满足里氏替换原则
    }
}

运行一下,输出的结果竟然是Rectangle和100,而不是Rectangle和50。

So,大家在设计类的体系结构的时候,一定要注意哈。举一个OK的例子:

比如今年公司年会,对于抽奖环节,全员参与。Boss可以抽奖、开发汪可以、运维汪也可以,QA小妹也可以,那么就是满足里氏替换原则的。祝大家年会都能抽中大奖!

    参考《涉及模式之禅》里面的一句话:在项目中,采用里氏替换原则的时候,应该尽量避免子类的“个性”,一旦子类有“个性“,这个子类和父类之间的关系就很难调和了。

 

最后,欢迎大家批评指正哈!

 

参考:

https://en.wikipedia.org/wiki/Liskov_substitution_principle

http://blog.csdn.net/u011288271/article/details/52497602

http://www.oodesign.com/liskov-s-substitution-principle.html

转载于:https://my.oschina.net/mingshashan/blog/1618728

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值