设计模式的七大原则(4) --里氏替换原则
前言
上一节中我们介绍了,依赖倒置,依赖倒置利用抽象的稳定性来架构我们的系统,是我们经常能遇到的一种原则,比如说面向接口编程。
这一节中,我们来说说里氏替换原则,这个原则其实非常非常的简单,其实与依赖倒置相结合来看,就是希望我们用抽象的方法来构建项目而非具体的实现,里氏替换原则就是推荐我们不要重写父类中具体的实现来构建我们的项目。
我们来深入研究研究。
基本介绍
- 继承包含这样一层含义:父类中凡是已经实现好的方法,实际上是在设定规范和契约,虽然它不强制要求所有的子类必须遵循这些契约,但是如果子类对这些已经实现的方法任意修改,就会对整个继承体系造成破坏。
- 继承在给程序设计带来便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能产生故障
那么翻译成比较容易理解的话,就是说,子类一般不该重写父类的方法,因为父类的方法一般都是对外公布的接口,是具有不可变性的,你不该将一些不该变化的东西给修改掉。
上述只是通常意义上的说法,很多情况下,我们其实不必要太过于在意这个原则,因为相对于继承带给我们的好处,很多时候我们会忽略掉其带来的弊端。比如缺省适配器,装饰器模式等一些设计模式
不过就算如此,如果你真的遇见了不得不重写父类方法的场景,那么请你考虑,你是否真的要把这个类作为子类出现在这里,或者说这样做所换来的是否能弥补你失去的东西,比如子类无法代替父类工作,那么就意味着如果你的父类可以在某一个场景里工作的很正常,那么你的子类当然也应该可以,否则就会出现下述场景。
案例
//某一个类 public class someoneclass { //有某一个方法,使用了一个父类类型 public void someonemethod(parent parent){ parent.method(); } }
父类代码如下
public class parent { public void method(){ system.out.println("parent method"); } }
结果我有一个子类把父类的方法给覆盖了,并且抛出了一个异常。
public class subclass extends parent{ //结果某一个子类重写了父类的方法,说不支持该操作了 public void method() { throw new unsupportedoperationexception(); } }
这个异常是运行时才会产生的,也就是说,我的someoneclass并不知道会出现这种情况,结果就是我调用下面这段代码的时候,本来我们的思维是parent都可以传给someonemethod完成我的功能,我的subclass继承了parent,当然也可以了,但是最终这个调用会抛出异常。
public class client { public static void main(string[] args) { someoneclass someoneclass = new someoneclass(); someoneclass.someonemethod(new parent()); someoneclass.someonemethod(new subclass()); } }
这就相当于埋下了一个个陷阱,因为本来我们的原则是,父类可以完成的地方,我用子类替代是绝对没有问题的,但是这下反了,我每次使用一个子类替换一个父类的时候,我还要担心这个子类有没有给我埋下一个上面这种炸弹。
所以里氏替换原则是一个需要我们深刻理解的原则,因为往往有时候违反它我们可以得到很多,失去一小部分,但是有时候却会相反,所以要想做到活学活用,就要深刻理解这个原则的意义所在。
总结
到这里我们已经掌握了四个原则(单一职责原则,接口隔离原则,依赖倒置原则,里氏替换原则)
下一个原则是非常非常重要的原则。甚至说,我们前面讲的都是为了下一个开闭原则做的准备也不为过。所以说掌握这四种原则是非常非常重要的。