设计模式入门
场景:某公司做一款鸭子游戏,设计一个鸭子超类,并让各种鸭子继承此超类(图1)。现在公司想让鸭子飞。于是设计师很快速的在超类中添加了一个fly()方法,并因此很高兴。结果客户发现所有类型的鸭子都能飞,就连木头鸭子也是(图2)。
【请你思考:在超类中添加fly()方法,导致所有继承超类的子类都具有这一方法,如果你是设计师会怎么做?来看看设计师怎么做的吧。】
设计师思考:那我就把不能飞的鸭子里的fly()方法覆盖掉(图3)
【请你思考:利用继承会有那些优点、缺点?
好处:
- A:提高了代码的复用性。
- B:提高了代码的维护性。
- C:让类与类产生的关系,是多态的前提
缺点:
- 类的耦合性增强了。(改变父类,结果子类一定要继承父类,想不继承都不行。这就是弊端)】
结果:导致添加不能飞的鸭子时,必须在鸭子类中添加覆盖方法,这导致代码冗余
覆盖的方法不能让公司满意,于是设计师又想解决办法:那就把fly()方法从超类中个提取出来,放进一个flyable接口中,只有会飞的鸭子实现接口,避免所有的鸭子都会飞。(图4)
公司主管又发火了:笨蛋,这样重复的代码就会增多,而且如果所有的子类都稍微修改一下飞行行为,你该怎么办?
设计师思考:有没有一种即对代码影响最想,还可以画最少时间重做代码
【我想说:设计师因为解决问题而解决问题,忘了去发掘最根本的问题,导致走了很多冤枉路,所以不要以为解决问题的思路就是问题的定义,我们应该先发现最本质的问题】
现在把问题归零......
找出变和不变的部分,然后把变得部分分装起来,让其他部分不受影响
【请你思考:这里变和不变的部分分别是什么?】
小编理解:变:有些鸭子不能飞,有些鸭子能飞;不变:超类中鸭子具有飞,游泳,叫等行为
接下来设计鸭子的行为:针对接口编程,而不是针对实现编程
【请你思考:针对接口编程和针对实现编程的区别】
例子:
声明变量d为Dog类型(是animal具体实现,会导致我们针对具体编程)
Dog d=new Dog();
d.bark
我们知道对象是狗,现在利用animal进行多台调用
Animal animal =new Dog();
animal.makeSound();
这样我们不需要知道子类的是类型是什么,直观性如何进行makeSound()动作就可以了
a.getAnimal();
a.makeSound();
实现鸭子的行为:再次,我们有两个接口,flyBehavior和swimBehavior 还有他们对应的类,负责实现具体的行为(图5)