设计模式六大原则之----里氏替换原则

前端之家收集整理的这篇文章主要介绍了设计模式六大原则之----里氏替换原则前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

一、定义

所有引用基类的地方,必须能透明的使用其子类对象。通俗的说:遵循里氏替换原则的代码,只要父类出现的地方就可以使用子类来替换它而不会产生任何错误,使用者不需要知道用的是父类还是子类。
它的核心是继承

友情提醒:xmind导出的图片有点模糊,请放大查看

二、优缺点

它的核心是继承,它的优缺点也是继承的优缺点

2.1 优点

2.2 缺点

三、重点

  • 返回值范围
    • 子类返回值S,父类返回值F,根据里氏替换原则,F范围必须大于S
  • 重载约束

四、 注意点

如果想要遵循里氏替换原则,那么尽量避免让子类拥有自己单独的属性方法,子类个性多了,子父类关系将难以调和

五、案例

路边摆摊打气球,我们可以用玩具枪射击,也可以用仿真枪射击。用代码描述出来。

5.1 遵循里氏替换原则代码实现

/**
 * 枪的抽象类,包含抽象方法和一个成员变量
 *
 * Created by rytong on 2017/11/14.
 */

public abstract class IGun {
    protected static final String TAG = "IGun";

    public abstract void shoot();
}

玩具枪类,仿真枪类似:

/**
 * 玩具枪类
 * Created by rytong on 2017/11/14.
 */

public class PlayerGun extends IGun {

    @Override
    public void shoot() {
        Log.e(TAG,"用玩具枪打气球");
    }
}

打气球的玩家:

/**
 * 打气球的玩家
 * Created by rytong on 2017/11/14.
 */

public class Player {
    IGun gun;

    public Player(IGun gun) {
        this.gun = gun;
    }
    public void shoot(){
        gun.shoot();
    }
}

玩家打气球:

IGun iGun = new PlamingGun();
    new Player(iGun).shoot();

    IGun iGun1 = new PlayerGun();
    new Player(iGun1).shoot();

玩家打了两枪,结果:

Log的TAG是继承的父类,射击方法是实现的父类的抽象方法

11-14 21:04:49.084 20053-20053/com.designpatterndisclipline E/IGun: 使用仿真枪打气球
11-14 21:04:49.084 20053-20053/com.designpatterndisclipline E/IGun: 用玩具枪打气球

5.2 修改逻辑模拟不严格遵循里氏替换原则可能存在的问题

给IGun增加两个方法,一个内部调用,一个开放出来player调用

/**
 * 枪的抽象类,包含抽象方法和一个成员变量
 *
 * Created by rytong on 2017/11/14.
 */

public abstract class IGun {
    protected static final String TAG = "IGun";

    public abstract void shoot();

    private void preBullet(){
        Log.e(TAG,"先准备好子弹才能射击。");
    }

    public void fire(){
        preBullet();
        shoot();
    }
}

PlayerGun不遵循里氏替换原则,覆盖父类的成员变量和方法,而PlamingGun完全遵循里氏替换原则。

/**
 * 玩具枪类
 * Created by rytong on 2017/11/14.
 */

public class PlayerGun extends IGun {

    private String TAG = "PlayerGun";

    @Override
    public void shoot() {
        Log.e(TAG,"用玩具枪打气球");
    }

    @Override
    public void fire() {
//        super.fire();
        Log.e(TAG,"我在玩玩具枪,不打气球");
    }
}

/**
 * 仿真枪类
 * Created by rytong on 2017/11/14.
 */

public class PlamingGun extends IGun {
    @Override
    public void shoot() {
        Log.e(TAG,"使用仿真枪打气球");
    }
}

修改玩家射击的方法

/**
 * 打气球的玩家
 * Created by rytong on 2017/11/14.
 */

public class Player {
    IGun gun;

    public Player(IGun gun) {
        this.gun = gun;
    }
    public void shoot(){
        gun.fire();
    }
}

玩家射击气球:

IGun iGun = new PlamingGun();
    new Player(iGun).shoot();

    IGun iGun1 = new PlayerGun();
    new Player(iGun1).shoot();

执行结果:

11-14 21:17:50.800 28393-28393/com.designpatterndisclipline E/IGun: 先准备好子弹才能射击。
11-14 21:17:50.800 28393-28393/com.designpatterndisclipline E/IGun: 使用仿真枪打气球
11-14 21:17:50.802 28393-28393/com.designpatterndisclipline E/PlayerGun: 我在玩玩具枪,不打气球

如果设计时规定了要遵循里氏替换原则那么就要严格遵守,否则在编程过程中往往会发生一些难以预料的错误,也就是你的代码的bug率会大大提升。

猜你在找的设计模式相关文章