
ters or references to base classes must be able to use objects ofderived classes without knowing it.
所有引用基类的地方必须能透明地使用其子类的对象。
第二个定义是最清晰明确的,通俗点讲,只要父类能出现的地方子类就可以出现,而且替换为子类还不产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。但是,反过来就不行了,有子类出现的地方,父类未必就能适应。
2.2 纠纷不断,规则压制 里氏替换原则为良好的继承定义了一个规范,一句简单的定义包含了四层含义:
子类必须完全实现父类的方法我们在做系统设计时,经常会定义一个接口或抽象类,然后编码实现,调用类则直接传入接口或抽象类,其实这里已经使用了里氏替换原则。我们举个例子来说明这个原则,大家都打过CS吧,非常经典的FPS类游戏,我们来描述一下里面用到的,类图如图2-1所示。
图2-1 CS游戏中的类图
的主要职责是射击,如何射击在各个具体的子类中定义,是单发射程比较近,威力大射程远,用于扫射。在士兵类中定义了一个方法killEnemy,使用来杀敌人,具体使用什么来杀敌人,调用的时候才知道,AbstractGun类的源程序如代码清单2-1所示。
代码清单2-1 的抽象类
1
2
3
4
5
6
7
public abstract class AbstractGun {
//用来干什么的?射击杀戮!
public abstract void shoot();
}
手 、、的实现类如代码清单2-2所示。
代码清单2-2 手 、、的实现类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class Handgun extends AbstractGun {
//手 的特点是携带方便,射程短
@Override
public void shoot() {
System.out.println('射击...');
}
}
public class Rifle extends AbstractGun{
//的特点是射程远,威力大
public void shoot(){
System.out.println('射击...');
}
}
public class MachineGun extends AbstractGun{
public void shoot(){
System.out.println('扫射...');
}
}
有了,还要有能够使用这些的士兵,其源程序如代码清单2-3所示。
代码清单2-3 士兵的实现类
1
2
3
4
5
6
7
8
9
10
11
public class Soldier {
public void killEnemy(AbstractGun gun){
System.out.println('士兵开始杀人...');
gun.shoot();
}
}
注意粗体部分,定义士兵使用来杀敌,但是这把是时抽象的,具体是还是需要在上战场前(也就是场景中)前确定。场景类Client的源代码如代码清单2-4所示。
代码清单2-4 场景类
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Client {
public static void main(String[] args) {
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-21726-1.html