2.2.3 企鹅不是鹅
里氏替换原则利用抽象实现了在不修改现有代码的情况下扩展新方法的功能。
小码路自从开了服装店,空闲时间很少,忙了半年,终于抽出一个周末去附近的动物园逛逛。
(1)主题——企鹅不是鹅
小码路来到了“里氏替换禽鸟馆”,如图2-4所示。
▲图2-4 “里氏替换禽鸟馆”
“里氏替换禽鸟馆”里企鹅和鹅正在赛跑,请用里氏替换原则计算两者前进100米分别用了多少时间。
(2)设计——扩展源于抽象
假设需要解决的实际问题是这样:分别计算企鹅和鹅前进100米用的时间。要解决这个问题,编程时可以把这两种动物写成两个不同的类,通过调用类中不同的方法来进行计算。假如又想计算另外一个动物(孔雀)跑100米用的时间,编程时又要建立一个孔雀类和相应的方法。那么,有没有一种仅仅设计一个类,却可以计算多种动物跑100米所用时间的方法呢?
这可以使用里氏替换原则进行解决。
这时候小码路想到了抽象这个概念,而里氏替换原则正是抽象的最佳体现,用派生类的对象代替基类对象,小码路写下了此题的求解步骤。
第一步:里氏替换原则的核心是抽象,正所谓扩展源于抽象,利用抽象方法完成对现有基类的扩展和替换。
第二步:设计中有抽象,那么必然存在一个抽象基类,对应的派生类企鹅类和鹅类继承自这个抽象基类,分别实现各自的具体方法。
第三步:设计一个计算用时类,作为客户端的入口,这个类根据不同动物的奔跑速度计算各自跑100米的用时。
据此,小码路画出了解决上述实际问题的UML类图,如图2-5所示,有了这个类图,代码就容易实现了。
▲图2-5 解决实际问题的UML类图
图2-5中明确了计算不同动物跑100米的用时的程序设计清单,这个程序设计清单主要包括如下内容。
① 里氏替换原则的核心——抽象。Animal类是一个抽象基类,声明一个setFlySpeed (double speed)抽象方法,派生类Penguin和派生类Goose分别继承自抽象基类Animal,并分别组成EIT造型,实现各自的setFlySpeed(double speed)方法。
② 软件设计流程的入口。calTime类是客户端的入口,其中的类方法showcalTime(Animal* an, double sp)通过传入的不同的Animal对象,调用不同动物的setFlySpeed(double speed)方法,从而计算不同动物跑100米所用的时间。