一个鸭子的应用
假设我们需要设计一个鸭子的应用,可以生成各种各样的鸭子,那么根据面向对象的做法,我们需要首先创建一个鸭子的基类,然后再利用继承的方式来生成各种各样的鸭子类型,如下所示: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
36
37
38
39
40
41
42
43
44
45
46
47
48package com.changyuan.demo;
abstract class Duck{
public void quack(){
System.out.println("quack!");
}
public void swim(){
System.out.println("I am swimming!");
}
abstract public void display();
}
class MallarDuck extends Duck{
public void display(){
System.out.println("I am MallarDuck");
}
}
class RedHeadDuck extends Duck{
public void display(){
System.out.println("I am RedHeadDuck");
}
}
class RubberDuck extends Duck{
public void quack(){
System.out.println("zhizhi!");
}
public void display(){
System.out.println("I am RubberDuck");
}
}
public class helloWorld {
public static void main(String[] args) {
MallarDuck mallarDuck = new MallarDuck();
mallarDuck.quack();
mallarDuck.swim();
mallarDuck.display();
RedHeadDuck redHeadDuck = new RedHeadDuck();
redHeadDuck.quack();
redHeadDuck.swim();
redHeadDuck.display();
RubberDuck rubberDuck = new RubberDuck();
rubberDuck.quack();
rubberDuck.swim();
rubberDuck.display();
}
}
这里我们生成了三种鸭子,它们重写了基类的相关方法,实现了我们的目的。
那么我们如果想要鸭子会飞呢?
那么就需要给duck基类添加一个fly的方法。
1 | abstract class Duck{ |
但是这样有一个问题,不是所有的鸭子都会飞,比如我们可以新创建一个橡皮鸭的类,这个类也继承了基类的fly方法,它也会飞,这就不合适了。那么有没有解决方法呢?有,可以在橡皮鸭的类中我们重写fly方法,让他什么都不做就好了。但是这样的效果并不好。
给基类增加了方法,会导致它的所有的子类都需要进行排查甚至修改。这样子影响太大。
那么其他的解决方法呢?
利用接口
现在我们引入第一个设计原则:
分类应用代码中的变化部分以及不变部分
我们看我们的duck类,不变的是swim和display,而fly和quack是每个鸭子可能有也可能没有的,那么可以用接口来承载
引入第二个原则:
针对接口编程,而不是针对实现编程
我们可以针对变化的部分利用接口来表示它们的行为
针对接口编程有一个优点,就是可以用基类调用子类的方法,这样就可以实现在运行的时候才指定具体实现的对象。
如下所示我们可以利用基类做多态的调用1
2
3
4
5Dog dog = new Dog();
dog.bark()
Animal animal = new Dog();
animal.makeSound();
我们需要重新设计Duck类,将变化的部分抽出到一个新的类中,不变的部分保留。
首先我们设计两个新的接口
1 | public interface QuackBehavior { |
然后新的类实现定义的接口,分别定义了3种声音以及2种飞行模式
1 | public class Quack implements QuackBehavior{ |
1 | public class FlyWithWings implements FlyBehavior{ |
有了上面的类,我们就可以重新设计Duck类,利用基类可以多态的调用的原则,我们首先给duck类定义两种行为,一个为flyBehavior,一个为quackBehavior。
1 | abstract class Duck{ |
测试代码如下:
1 | class MallarDuck extends Duck{ |
我们定义了一个MallarDuck,在它的构造函数里面指定了quackBehavior和flyBehavior的行为。这样每当我们新创建类的时候,就可以直接指定好这两个行为了。这对扩展及其友好。
上面的实现还是太死了,它在构造函数中写死了行为,实际上我们可以动态的设定行为。
我们可以在基类上添加两个set方法,这样就可以动态的改变类的行为了。
1 | abstract class Duck{ |
然后我们新增加一个类:
1 | public class FlyRocketPower implements FlyBehavior { |
然后我们就可以在运行的时候动态的改动对象的状态了。
1 | public class helloWorld { |
显示结果如下:
1 | I am ModelDuck |
下面是上面的整个逻辑的类图
下面我们引入第三个设计的原则:
多用组合,少用继承
上面的所有的代码就解释了一个设计模式:
策略模式
策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立与使用算法的客户。
代码路径:
https://github.com/changyuanchn/DesignPattern/tree/main/src/com/changyuan/strategyPattern