其他分享
首页 > 其他分享> > 夯实设计原则之里氏替换原则

夯实设计原则之里氏替换原则

作者:互联网

All Rights Reserved © jackiegu.cn

理念:

所有引用基类(父类)的地方必须能透明的使用其子类的对象;

在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的是一个子类对象的话,那么它不一定能够使用基类对象;如:小明喜欢动物,那么他一定喜欢猫,因为猫是动物的子类;反过来,小明喜欢猫,不能据此断定出他喜欢动物,可能他并不喜欢狗,虽然狗也是动物;

里氏替换原则是实现开闭原则的重要方式之一,由于使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来对对象进行定义,再在运行时确定其子类类型,用子类对象来替换父类对象;

案例:

小明在工作中接到一个需求,需要为项目中的普通用户和VIP用户发送短信;于是他先定义了两个用户类:NormalUser普通用户、VipUserVIP用户,如下:

/**
 * 普通用户
 */
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