设计模式--里氏替换原则
发布时间:2020-12-13 22:13:44 所属栏目:百科 来源:网络整理
导读:里氏替换原则是针对继承的,它为良好的继承定义了一个规范。 从学习面向对象编程开始,就知道了继承的概念,是面向对象的三大特征之一,但是继承究竟有什么好的呢?凡事都有两面性,在尽享继承带来的好处的同时,它又给我们带来什么弊端呢?这里我们来回顾一
里氏替换原则是针对继承的,它为良好的继承定义了一个规范。 从学习面向对象编程开始,就知道了继承的概念,是面向对象的三大特征之一,但是继承究竟有什么好的呢?凡事都有两面性,在尽享继承带来的好处的同时,它又给我们带来什么弊端呢?这里我们来回顾一下: 好处: 1、代码共享,减少创建类的工作量,每个子类都拥有父类的方法和树形; 2、提高代码的重用性; 3、提高代码的可扩展性; 4、提高项目或产品的开放性; 缺点: 1、继承是侵入式的,只要继承就必须拥有父类所有的树形和方法; 2、降低代码的灵活性,子类必须继承父类的树形和方法,让子类多了很多的约束; 3、增强了耦合性,当父类的变量、常量和方法被修改时,必须考虑到子类的修改,而且在缺乏规范的环境下,这种修改可能带来非常糟糕的接口——大量的代码需要重构。 里氏替换原则就是针对继承的缺点而定义的规范,它的简明的定义如下: 只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本不需要知道是父类还是子类。但是,反过来就不可以了,有子类出现的地方,父类未必就能适应。 简单的定义包含了4层含义: 1、子类必须完全实现父类的方法 举个例子,CS游戏中的枪,如下类图: public abstract class AbstractGun { //枪都有一个特征,就是射击 public abstract void shoot(); } public class HandGun extends AbstractGun { @Override public void shoot() { System.out.println("手枪射击..."); } } public class Rifle extends AbstractGun { @Override public void shoot() { System.out.println("步枪射击..."); } } public class MachineGun extends AbstractGun { @Override public void shoot() { System.out.println("机枪射击..."); } } /** * 在类中调用其他类时务必使用父类或是接口,如果不能使用父类或是接口,则说明类的设计已经违背了LSP原则 * @author suo */ public class Soldier { private AbstractGun gun; public void setGun(AbstractGun gun){ this.gun=gun; } public void killEnemy(){ System.out.println("士兵开始杀敌人..."); gun.shoot(); } } public class Client { public static void main(String[] args) { Soldier soldier = new Soldier(); soldier.setGun(new Rifle()); soldier.killEnemy(); } } 运行结果如下: 士兵开始杀敌人... 步枪射击... 此时,如果有一个玩具手枪,不能用来射击,杀不死人,该怎么办?首先不能让玩具手枪继承自AbstractGun,因为它没有射击的特征,可以这么来做,让玩具手枪脱离继承,建立一个独立的父类,为了实现代码的重用,可以与AbstractGun建立关联委托关系,如下类图: (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |