java 设计原则(六)里氏替换原则

定义:如果对每一个类型T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都替换成o2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。
定义扩展:一个软件实体如果适用一个父类的话,那一定适用于其自类,所有引用父类的地方必须能透明地使用其自类的对象,子类对象能够替换父类对象,而程序逻辑不变。
引申意义:子类可以扩展父类的功能,但不能改变父类原有的功能。

含义1:子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
含义2: 子类可以增加自己特有的方法。
含义3:当子类的方法重载父类的方法时,方法的前置条件(即方法的输入/入参)要比父类的方法的输入参数更宽松。
含义4:当子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即方法的输入/输出值)要比父类更严格或相等。

优点1:约束继承泛滥,开闭原则的一种体现。
优点2:加强程序的健壮性,同时变更时也可以做到非常好的兼容性提高程序的维护性、扩展性。降低需求变更时引入的风险。


public class Reactangle {
    private long length;//长度
    public long getLength() {
        return length;
    }

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

    public long getWidth() {
        return width;
    }

    public void setWidth(long width) {
        this.width = width;
    }

    private long width;//宽度
}


public class Square extends Reactangle {
	//正方形的边长
    private long sideLength;
    //getLength() =getWidth() = getSideLength()
    public long getSideLength() {
        return sideLength;
    }
    public void setSideLength(long sideLength) {
        this.sideLength = sideLength;
    }
	//getLength() =getWidth() = getSideLength()
    @Override
    public long getLength() {
        return getSideLength();
    }
	//重写了 长方形设置宽的方法 正方形是长方形的特殊形式 边和长都是一样的
	//setWidth() = setLength() = setSideLength()
    @Override
    public void setLength(long length) {
        setSideLength(length);
    }
	//getLength() =getWidth() = getSideLength()
    @Override
    public long getWidth() {
        return getSideLength();
    }
	//重写了 长方形设置宽的方法 正方形是长方形的特殊形式 边和长都是一样的
	//setWidth() = setLength() = setSideLength()
    @Override
    public void setWidth(long width) {
        setSideLength(width);
    }
}


public class Test {
	//这是长方形的一个resize方法 判断宽度如果小于等于长度就增加1
    public static void resize(Reactangle rectangle){
        while(rectangle.getWidth() <= rectangle.getLength()){
            rectangle.setWidth(rectangle.getWidth() +1);
            System.out.println("Width:" +rectangle.getWidth() +"length" +rectangle.getLength());
        }
        System.out.println("resize方法结束:" +rectangle.getWidth() +"length" +rectangle.getLength());

    }

    public static void main(String[] args) {
        Reactangle rectangle =new Reactangle();
        rectangle.setWidth(10);
        rectangle.setLength(20);
        resize(rectangle);
    }
   }

当我们 要用 Square 扩展 这个 Reactangle 类 期望达到的是 只要重写父类的方法 按照一定的标准 适用Reactangle 这个类的方法一定也适用于Square这个类 但是 resize()这方法并不能适用于 Square 因为 resize在判断长度的时候 会比较 边长 和宽度 大小 但正方形边长都一样 这样resize 会陷入while死循环。

public static void main(String[] args) {
        Square sq =new Square(10);
        resize(sq);
    }

上面可以看出 Square 不适合 里式替换 原则 那怎么样 设计 才能进行 约束防止继承的泛滥呢。

public interface Quadrangle {
    long getWidth();
    long getLength();
}

public class Reactangle implements Quadrangle {
    private long length;

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

    public void setWidth(long width) {
        this.width = width;
    }

    private long width;

    @Override
    public long getWidth() {
        return width;
    }

    @Override
    public long getLength() {
        return length;
    }
}


public class Square implements Quadrangle {
    public void setSideLength(long sideLength) {
        this.sideLength = sideLength;
    }

    private long sideLength;

    public Square(int sideLength) {
        this.sideLength = sideLength;
    }


    @Override
    public long getWidth() {
        return sideLength;
    }

    @Override
    public long getLength() {
        return sideLength;
    }
}

在这里插入图片描述

//这里传入的是四边形 类型
 public static void resize(Quadrangle rectangle){
 		//下面会报错 因为 四边形方法里没有setWidth()方法 这样就很好的约束了 子类 的行为。 所以上面只能传入(Reactangle rectangle)

        while(rectangle.getWidth() <= rectangle.getLength()){
            rectangle.setWidth(rectangle.getWidth() +1);
            System.out.println("Width:" +rectangle.getWidth() +"length" +rectangle.getLength());
        }
        System.out.println("resize方法结束:" +rectangle.getWidth() +"length" +rectangle.getLength());

    }

里氏替换原则 强调子类的行为 应与父类保持一致 可以达到 子类 替换 掉父类时 功能保持 程序P的功能 能保持不变。

方法入参/返回

public class Base {
//当父类写成Map 或者HashMap 传参 都会调用子类 重写方法
    public  void  method(HashMap map){
        System.out.println("父类被执行");
    }
}
public class Child extends Base {

    @Override
    public void method(HashMap map) {
        System.out.println("子类HashMao 入参方法被执行");
    }
    //子类这个方法不能 比父类的 范围大 Map 比 HashMap 范围大
    //所以这个方法 是不会被执行的
    public void method(Map map) {
        System.out.println("子类被执行");
    }
}
public class Test {
    public static void main(String[] args) {
        Base a = new Child();
        a.method(new HashMap());
    }
}

同理 子类的返回 值比 父类的返回值 范围更大 就会直接报错。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值