夯实设计原则之里氏替换原则
作者:互联网
All Rights Reserved © jackiegu.cn
理念:
所有引用基类(父类)的地方必须能透明的使用其子类的对象;
在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的是一个子类对象的话,那么它不一定能够使用基类对象;如:小明喜欢动物,那么他一定喜欢猫,因为猫是动物的子类;反过来,小明喜欢猫,不能据此断定出他喜欢动物,可能他并不喜欢狗,虽然狗也是动物;
里氏替换原则是实现开闭原则的重要方式之一,由于使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来对对象进行定义,再在运行时确定其子类类型,用子类对象来替换父类对象;
案例:
小明在工作中接到一个需求,需要为项目中的普通用户和VIP用户发送短信;于是他先定义了两个用户类:NormalUser
普通用户、VipUser
VIP用户,如下:
/**
* 普通用户
*/
public class NormalUser {
private String name;
private String mobileNo;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMobileNo() {
return mobileNo;
}
public void setMobileNo(String mobileNo) {
this.mobileNo = mobileNo;
}
}
/**
* VIP用户
*/
public class VipUser {
private String name;
private String mobileNo;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMobileNo() {
return mobileNo;
}
public void setMobileNo(String mobileNo) {
this.mobileNo = mobileNo;
}
}
然后他再定义了一个短信发送器类SmsSender
,里面分别实现了对普通用户和VIP用户的短信发送功能,如下:
/**
* 短信发送器
*/
public class SmsSender {
/**
* 给普通用户发送短信
*
* @param normalUser 普通用户
*/
public void send(NormalUser normalUser) {
System.out.println("发送短信给用户: " + normalUser.getMobileNo());
}
/**
* 给VIP用户发送短信
*
* @param vipUser VIP用户
*/
public void send(VipUser vipUser) {
System.out.println("发送短信给用户: " + vipUser.getMobileNo());
}
}
从上面的案例来看, SmsSender
类中给普通用户和VIP用户发送短信的逻辑是一样的,很明显的有代码重复;而且在项目中如果新增了一种超级用户
的用户类型,也需要发送短信时,那就不得不修改SmsSender
类的代码,也就违背了开闭原则;
同样是上面的案例,当懂得里氏替换原则的小红遇到时,会怎样来设计呢?接下来请看:
首先定义一个用户行为接口类IUser
,如下:
/**
* 用户行为接口
*/
public interface IUser {
String getName();
void setName(String name);
String getMobileNo();
void setMobileNo(String mobileNo);
}
然后再重新定义普通用户NormalUser
和VIP用户VipUser
类,让这两个用户类都实现IUser
接口,如下:
/**
* 普通用户
*/
public class NormalUser implements IUser {
private String name;
private String mobileNo;
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getMobileNo() {
return mobileNo;
}
@Override
public void setMobileNo(String mobileNo) {
this.mobileNo = mobileNo;
}
}
/**
* VIP用户
*/
public class VipUser implements IUser {
private String name;
private String mobileNo;
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getMobileNo() {
return mobileNo;
}
@Override
public void setMobileNo(String mobileNo) {
this.mobileNo = mobileNo;
}
}
最后重新定义短信发送器类SmsSender
,如下:
/**
* 短信发送器
*/
public class SmsSender {
/**
* 给用户发送短信
*
* @param user 用户
*/
public void send(IUser user) {
System.out.println("发送短信给用户: " + user.getMobileNo());
}
}
从上面小红的代码来看, SmsSender
类中给不同用户发送短信的重载方法已不存在,同时新增了一个以IUser
为参数的发送短信的方法,以后不管为什么类型的用户类型发送短信,都可以采用这个方法;解决了小明版本的代码重复问题,同时在新增用户类型发送短信时也不用去修改SmsSender
类的代码,遵循了开闭原则,SmsSender
类的send
方法的IUser
参数也遵循了里氏替换原则;
标签:name,原则,里氏,void,mobileNo,用户,夯实,public,String 来源: https://blog.csdn.net/gu19930914/article/details/116799125