史无前例的设计模式-里氏替换原则

一、概念

里氏替换原则:Liskov Substitution Principle,检查LSP。子类对象能够替换程序中父类对象出现的任何地方,并能保证替换完后程序的逻辑行为不变以及替换前后的逻辑语义和结果正确性不被破坏。
例如:父类逻辑是a+b,子类逻辑是a-b,参数和返回都一样,但是逻辑变了,这就不符合里氏替换原则。逻辑语义和结果的正确性得到了破坏。

二、案例

如下HealthCheck健康检查父类,有MysqlHealthCheck子类继承它,基本语义就是连接到Mysql发SELECT 1;


public class HealthCheck{
  public Response doCheck(HealthCheckEntity entity) {
    // ...
  }
}

public class MysqlHealthCheck extends HealthCheck {
  private String username;
  private String pwd;

  public MysqlHealthCheck (HealthCheckEntity entity, String username, String pwd) {
    super(entity);
    this.username= username;
    this.pwd= pwd;
  }

  @Override
  public Response sendRequest(HealthCheckEntity entity) {
    if (StringUtils.isNotBlank(username) && StringUtils.isNotBlank(pwd)) {
		entity.setUsername(username);
		entity.setPwd(pwd);
    }
    return super.sendRequest(entity);
  }
}

public class Demo {    
  public void demoFunction(HealthCheck healthCheck) {    
    HealthCheckEntity entity = new HealthCheckEntity ();
    //...省略设置request中数据值的代码...
    Response response = healthCheck.sendRequest(entity);
    //...省略其他逻辑...
  }
}

// 里式替换原则
Demo demo = new Demo();
demo.demofunction(new MysqlHealthCheck (/*省略参数*/););

在上面的代码中,子类MysqlHealthCheck的设计完全符合里氏替换原则,可以无缝替换父类出现的任何位置并且原代码逻辑行为不变且正确性也不会得到破坏。但是发现这不就是多态吗?和多态没啥区别呀。下面来看和多态的区别。

三、和多态的区别

也称哪些设计违背了里氏替换原则

  • 子类违背父类声明要实现的功能

最简单的例子就是父类是按照时间倒叙排序,子类是按照时间升序排序。

  • 子类违背父类对出入参以及异常的约定

比如:父类要求运行报错的时候返回null,没查到数据但是没报错返回new Object();,但是子类重写过后的方法报错直接返回异常了,得不到父类期待的null值。

  • 子类违背父类注释中所罗列的任何一个特殊说明

比如:父类写的是参数a不能大于100,而子类重写后的判断条件没有这个100限制,这也算违背里氏替换原则。

以上三点,多态是完全不管的。所以里氏替换是事精,而多态很随和。

违背里氏替换的案例说明:
假设上面的HealthCheck的子类MysqlHealthCheck的数据库用户名密码没传的话就抛出异常,这就违背了里氏替换,因为父类要求不做任何限制,而你却强行往里加。

// 其他类不变

public class MysqlHealthCheck extends HealthCheck {
  private String username;
  private String pwd;

  public MysqlHealthCheck (HealthCheckEntity entity, String username, String pwd) {
    super(entity);
    this.username= username;
    this.pwd= pwd;
  }

  @Override
  public Response sendRequest(HealthCheckEntity entity) {
  	// 加了限制,违背了里氏替换原则
	if (StringUtils.isBlank(username) || StringUtils.isBlank(pwd)) {
		throw new RuntimeException();
	}
	entity.setUsername(username);
	entity.setPwd(pwd);
    return super.sendRequest(entity);
  }
}

四、总结

子类可以新增逻辑或者优化,但是不允许改变父类的语义,比如典型的就是父类要求按照id倒叙排序,你子类不可弄成按照id升序排序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

【原】编程界的小学生

没有打赏我依然会坚持。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值