`

面向对象的原则、模式、语言及框架(五)

阅读更多
Liskov替换原则
我们前面说了开闭原则OCP,其背后的主要机制是抽象和多态,但在静态语言中(如c++,java),支持抽象和多态的关键机制之一便是继承,正是有了继承,我们才能够
抽象出接口/基类,然后在子类中实现继承而来的抽象方法,或覆写基类已实现的方法
来定制子类。这样我们才能只通过扩展来实现新增的功能。
但是按照什么规则,我们才能设计出最佳的继承层次呢,以及什么样才是最佳的继承体
系呢?Liskov替换原则回答了这个问题。
下面我们就看看什么是Liskov替换原则(LSP):
LSP:子类型必须能够替换成它们的基类型。
LSP的重要性是不言而喻的,例如:
void f(BaseType bt){
  //使用bt来做事情
}

这时候如果我们传递一个子类型SubType的对象st:f(st);
如果这时候f出现一个错误的行为,那么SubType就违反了LSP,同时也导致了对
OCP的违反,因为我们要想这个方法对SubType也产生正确的行为,我们需要重新
修改f,对特定SupType进行定制操作,以便得到正确的行为,这样f对BaseType
的子类就不封闭了
我们看看Bob大叔举的一个违反LSP的例子:
public class Rectangle{
  protected int width;
  protected int hight;
 
  public void setWidth(int width){
     this.width = width; 
  }
  public void setHight(int hight){
     this.hight = hight;
 }
 public int getWidth(){
    return width;
 }
 public int getHight(){
   return hight;
 }
}

我们经常说继承是"Is-a",而组合是"has-a".这样如果一个的对象对于另一个类的对象
满足"is-a"关系,那么就应该把这个新类从原来那个类继承而来。
正方形是个矩形,因此把Square类视为Rectangle类的子类应该是合理的。"Is"被认为是
面向对象设计(OOA)的基本技术之一。但这会产生微妙但极为应该重视的问题。
但我们首先看到width,height两个变量对于Square来说是一种浪费,一般情况下,这种浪费是无关紧要的。但是setHight和setWidth对于Square来说是不合适的,因为正方形的长和宽应该相同的,我们为了确保这点,我们可以复写这两个方法:
public class Square extends Rectangle{
//others
 public void setWidth(int width){
     super.setWidth(width);
     super.setHight(width);
 }
  public void setHight(int hight){
     super.setHight(hight);
     super.setWidth(hight);
 }
}

这样似乎就满足了数学意义上的正方形了吧,但是我们考虑下面的函数
void testArea(Rectangle r){
  r.setWidth(2);
  r.setHeight(3);
  assert(r.area()==6);
}

当我们向testArea传递Square对象时,断言就会失败,因为testArea的编写者
不会认为高度的改变,会影响宽度。方法testArea表明Rectangle和Square的结构
是脆弱的,Square不能够替换掉Rectangle,因此Square和Rectagle之间的关系是违反了
LSP。
LSP让我们得出了一个非常重要的结论:一个模型,如果孤立的看,并不能发现问题,模型
的有效性只能通过它的客户程序来表现。如果孤立的看,最后那个版本的模型时自相容的,
但是如果从基类做出一些合理假设的程序员的角度来看,这个模型是有问题的。

但是有谁能知道使用者会做出怎样的假设呢?大多数的假设是很难预测的。事实上如果我们
试图去预测所有这种假设,我们所得到的系统将充满不必要复杂性的Bad Smell.所以通常最好的方法是之预测那些最明显的对于LSP违反情况而推迟其他的预测。
真正原因:
IS-A是关于行为的
Square和Rectangle这个显然合理的模型为什么会出现问题?毕竟Square就是Rectangle,
难道它们之间不存在is-a关系么?
对于不是testArea的编写者来说Square就是Rectangle是没有问题的,但对于testArea得编写者而言,Square对象绝对不是Square,应为Square的行为方式和testArea所期望的行为方式是不相容的。对象的行为方式才是软件真正关注的问题,LSP清楚地告诉我们,OOD中
is-a是对于行为方式而言的,行为方式的合理假设是客户程序所依赖的。
另外一个问题:
我们都知道Java的异常,子类不能比超类抛出更多的异常,这其实就是LSP原则。
结论:
OCP是OOD的核心原则,如果这个原则应用的有效,应用程序就会有更好的维护性、可重用性和健壮性,而LSP是OCP成为可能的主要原则之一,正是子类型的可替换性,才使得使用基类型的模块无需修改的情况下就能进行扩展。这种可替换性是开发人员可以隐式依赖的东西。
2
3
分享到:
评论

相关推荐

    JAVA设计模式六大原则详细讲解(面向对象语言通用)

    6.恰恰是告诉我们用抽象构建框架,用实现扩展细节的注意事项而已:单一职责原则告诉我们实现类要职责单一;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;接口隔离原则告诉我们在设计...

    敏捷软件开发:原则、模式与实践.pdf

     ●面向对象设计原则:本书包含了11个面向对象设计原则,涵盖了包的设计和类的设计。这是我所见过的对这方面内容讲解的最清晰、最彻底、最深刻的唯一的一本书。  ●设计模式:本书中讲述了23个设计模式,并都有...

    面向对象与UML资料

    面向对象语言及系统 19 第二节 面向对象的分析 20 OOA分析的任务 20 OOA分析的原则 20 OOA分析过程 20 第三节 面向对象的设计 20 设计的模型 20 设计的三条重要原则 21 面向对象设计的概念 21 面向对象的设计方法 21...

    写给大家看的面向对象编程书(第3版).[美]Matt Weisfeld(带详细书签).pdf

    此外,本书还讨论了各种与面向对象概念密切相关的应用主题,包括XML、UML建模语言、持久存储、分布式计算和客户/服务器技术等。  本书内容精炼,示例简单明了,适合各层次面向对象开发人员阅读,也是高校相关专业...

    06_面向对象设计1

    1. 针对特定平台(编程语言、操作系统、数据库、框架、 2. 应用面向对象设计的原则与模式进行优化 1. 单一职责原则SRP 2. 里氏替换原则LSP 3. 依

    asp.net 设计模式样章试读

    不必管模式本身所用的语言,可以将模式用于任何面向对象编程语言。 本书是为那些熟悉.NET框架但希望了解如何改进编码方式以及如何运用设计模式、设计原则和最佳实践来提高代码的可维护性和适应性的ASP.NET开发者而写...

    NET设计规范-.NET约定、惯用法与模式.part2

    2.2 框架设计的基本原则 10 2.2.1 场景驱动设计的原则 11 2.2.2 低门槛原则 17 2.2.3 自说明对象模型原则 20 2.2.4 分层架构原则 25 2.3 小结 27 第3章 命名规范 28 3.1 大小写约定 29 3.1.1 ...

    面向对象技术与UML课件及源代码-by 南邮-陈杨

    本书为中南大学精品教材立项项目,分为上下两篇共21章,涵盖了面向对象技术中Java开发环境配置、程序设计基础、面向对象原理以及UML的知识。本书使用的开发环境是JDK 1.6+Eclipse 3.3+Rational Rose 2003,逐步引领...

    ASP.NET设计模式-杨明军译(源码)

    不必管模式本身所用的语言,可以将模式用于任何面向对象编程语言。  《asp.net设计模式》是为那些熟悉.net框架但希望了解如何改进编码方式以及如何运用设计模式、设计原则和最佳实践来提高代码的可维护性和适应性的...

    Cocoa Design Patterns

    《Cocoa设计模式》介绍了Cocoa框架中用到的面向对象的设计模式。Cocoa框架是Apple的面向对象开发环境,用来开发:Mac OS X的应用程序。主要的开发语言为Objective-C,它是Mac下进行开发必不可少的开发环境。 《Cocoa...

    Java面试宝典和毕设PPT模板

    Java基础知识:包括Java语言的特性、面向对象编程、异常处理、集合框架、多线程等。确保你对Java核心概念和相关的API有很好的理解。 数据结构和算法:了解常见的数据结构(如数组、链表、栈、队列、树、图等)以及...

    论设计模式的重要性-《重学设计模式》

    一方面,设计模式教我们如何使用面向对象设计的原则解决各种问题; 另一方面,设计模式定义了一种通用语言(跟框架一样,统一一个标准),让大家在做系统设计的时候,能更有效的交流。 我们学习设计模块的核心...

    NET设计规范-.NET约定、惯用法与模式.part1

    2.2 框架设计的基本原则 10 2.2.1 场景驱动设计的原则 11 2.2.2 低门槛原则 17 2.2.3 自说明对象模型原则 20 2.2.4 分层架构原则 25 2.3 小结 27 第3章 命名规范 28 3.1 大小写约定 29 3.1.1 ...

    java8集合源码-orgfiles-computing:关于设计原则、编程语言、工具和框架的说明

    java8集合源码关于设计原则、编程语言、工具和框架的说明 设计原则 面向对象编程 在本节中,我们将描述涉及面向对象编程 (OOP) 的关键概念,以及为什么现代系统正在慢慢采用替代技术来替代以前作为理想 OOP 模式教导...

    修改代码的艺术2014版

    书中不仅讲述面向对象语言(Java、C#和C++)代码,也有专章讨论C这样的过程式语言。作者将理解、测试和修改代码的原理、技术和最新工具(自动化重构工具、单元测试框架、仿对象、集成测试框架等),与解依赖技术和...

    二十三种设计模式【PDF版】

    GoF 的《设计模式》是所有面向对象语言(C++ Java C#)的基础,只不过不同的语言将之实现得更方便地使用。 GOF 的设计模式是一座"桥" 就 Java 语言体系来说,GOF 的设计模式是 Java 基础知识和 J2EE 框架知识之间一...

    ThinkPHP 3.1.2 - PHP的开发框架MVC - 含Core,Extend,Example

    ThinkPHP 是一个免费开源的,快速、简单的面向对象的 轻量级PHP开发框架, 遵循Apache2开源协议发布,是为了敏捷WEB应用开发和简化企业应用开发而 诞生的。ThinkPHP从诞生以来一直秉承简洁实用的设计原则,在保持...

Global site tag (gtag.js) - Google Analytics