打字猴:1.70045465e+09
1700454650
1700454651 public static void main(String[]args){
1700454652
1700454653 //产生三毛这个士兵
1700454654
1700454655 Soldier sanMao=new Soldier();
1700454656
1700454657 sanMao.setGun(new ToyGun());
1700454658
1700454659 sanMao.killEnemy();
1700454660
1700454661 }
1700454662
1700454663 }
1700454664
1700454665 修改了粗体部分,把玩具枪传递给三毛用来杀敌,代码运行结果如下所示:
1700454666
1700454667 士兵开始杀敌人……
1700454668
1700454669 坏了,士兵拿着玩具枪来杀敌人,射不出子弹呀!如果在CS游戏中有这种事情发生,那你就等着被人爆头吧,然后看着自己凄惨地倒地。在这种情况下,我们发现业务调用类已经出现了问题,正常的业务逻辑已经不能运行,那怎么办?好办,有两种解决办法:
1700454670
1700454671 ❑在Soldier类中增加instanceof的判断,如果是玩具枪,就不用来杀敌人。这个方法可以解决问题,但是你要知道,在程序中,每增加一个类,所有与这个父类有关系的类都必须修改,你觉得可行吗?如果你的产品出现了这个问题,因为修正了这样一个Bug,就要求所有与这个父类有关系的类都增加一个判断,客户非跳起来跟你干架不可!你还想要客户忠诚你吗?显然,这个方案被否定了。
1700454672
1700454673 ❑ToyGun脱离继承,建立一个独立的父类,为了实现代码复用,可以与AbastractGun建立关联委托关系,如图2-3所示。
1700454674
1700454675
1700454676
1700454677
1700454678 图2-3 玩具枪与真实枪分离的类图
1700454679
1700454680 例如,可以在AbstractToy中声明将声音、形状都委托给AbstractGun处理,仿真枪嘛,形状和声音都要和真实的枪一样了,然后两个基类下的子类自由延展,互不影响。
1700454681
1700454682 在Java的基础知识中都会讲到继承,Java的三大特征嘛,继承、封装、多态。继承就是告诉你拥有父类的方法和属性,然后你就可以重写父类的方法。按照继承原则,我们上面的玩具枪继承AbstractGun是绝对没有问题的,玩具枪也是枪嘛,但是在具体应用场景中就要考虑下面这个问题了:子类是否能够完整地实现父类的业务,否则就会出现像上面的拿枪杀敌人时却发现是把玩具枪的笑话。
1700454683
1700454684 注意 如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承关系,采用依赖、聚集、组合等关系代替继承。
1700454685
1700454686 2.子类可以有自己的个性
1700454687
1700454688 子类当然可以有自己的行为和外观了,也就是方法和属性,那这里为什么要再提呢?是因为里氏替换原则可以正着用,但是不能反过来用。在子类出现的地方,父类未必就可以胜任。还是以刚才的关于枪支的例子为例,步枪有几个比较“响亮”的型号,比如AK47、AUG狙击步枪等,把这两个型号的枪引入后的Rifle子类图如图2-4所示。
1700454689
1700454690
1700454691
1700454692
1700454693 图2-4 增加AK47和AUG后的Rifle子类图
1700454694
1700454695 很简单,AUG继承了Rifle类,狙击手(Snipper)则直接使用AUG狙击步枪,源代码如代码清单2-7所示。
1700454696
1700454697 代码清单2-7  AUG狙击枪源码代码
1700454698
1700454699 public class AUG extends Rifle{
[ 上一页 ]  [ :1.70045465e+09 ]  [ 下一页 ]