GitHub 源码分享
微信搜寻:码农 StayUp
主页地址:https://gozhuyinglong.github.io
源码分享:https://github.com/gozhuyinglong/blog-demos
1. 一个简略的模仿鸭子游戏
咱们先来看一个模仿鸭子的游戏:游戏中会呈现各种鸭子,它们一边游泳戏水,一边呱呱叫。
通过一番调研后:
已知的鸭子品种有:野鸭(Mallard Duck)、红头鸭(Redhead Duck)、橡皮鸭(Rubber Duck)。
已知的鸭子行为有:游泳(Swim)、嘎嘎叫(Quack)、显示鸭子的样子(Display)。
上面是这些鸭子的外观:
需要明确,开搞!
1.1 是时候展现 OO 技术了~
为了可复用性,设计了一个鸭子超类Duck
,并让各种鸭子继承此超类:
- 该超类中实现了
swim()
、quack()
办法,因为每一种鸭子外观不同,所以display()
指定为形象办法(当然该类也是抽象类)。 - 各个子类具体实现了
display()
办法 - 因为橡皮鸭不会“嗄嗄叫”,所以重写了
quack()
办法为“吱吱叫”。
上面是 UML 类图:
1.2 Change!!!
咱们晓得软件开发的一个不变的真谛是:“变动”!
当初要求减少一种鸭子行为:航行(Fly),该怎么做呢?
如果持续应用继承,那么橡皮鸭是不会航行的,还是须要重写 fly()
办法。如下:
那如果再减少一种鸭子:钓饵鸭(Decoy Duck),这是只木头鸭子,它即不会叫,也不会航行 ……
看来继承是不能满足需要了!
1.3 应用接口怎么样?
将 fly()
办法和 quack()
抽离进去,做成接口,让领有该行为的鸭子对其进行实现。如下:
这仿佛解决了当初的问题!
但如果再减少 100 只鸭子呢?岂不是所有会航行或会叫的鸭子,都要实现一遍,没有达到代码的复用性。而且一旦要批改某个行为将是一件苦楚的事(比方将所有“吱吱叫”改成“仿真呱呱叫”)……
1.4 封装变动
有一个设计准则,恰好实用于下面模仿鸭子游戏的情况。
找出利用中可能须要变动之处,把它们独立进去,不要和那些不须要变动的代码混在一起。
换句话说,如果每次来新的需要,都会使某方面的代码发生变化,那么你就能够确定,这部分的代码须要被抽出来,和其余稳固的代码有所辨别。
这便是策略模式的精力所在,上面咱们来看该模式的具体介绍。
2. 策略模式
策略模式(Strategy Pattern)是一种行为型模式。该模式定义一系列的算法,把它们一个个封装起来,并使它们能够互相替换。该模式让算法的变动独立于应用它的客户。
Define a family of algorithms, encapsulate each one, and make them interchangeable.
该设计模式体现了几个设计准则:
- 封装变动
- 针对接口编程,而不是实现类
- 多用组合,少用继承
策略模式由三局部组成:
- Strategy(策略)
定义了所有策略的公共接口。上下文(Context)应用这个接口来调用某个具体策略(ConcreteStrategy)。
- ConcreteStrategy(具体策略)
Strategy 接口的实现,定义了一个具体的策略实现。
- Context(上下文)
定义了 Strategy 对象如何来应用,是策略算法的调用者。
3. 代码实现
咱们应用策略模式实现下面模仿鸭子游戏。
3.1 航行行为实现
定义航行行为接口
public interface Fly {void fly();
}
用翅膀航行实现类
public class FlyWithWings implements Fly {
@Override
public void fly() {System.out.println("用翅膀航行");
}
}
不会航行实现类
public class FlyNoWay implements Fly {
@Override
public void fly() {System.out.println("不会航行");
}
}
3.2 鸭叫行为实现
定义鸭叫行为接口
public interface Quack {void quack();
}
呱呱叫实现类
public class QuackGuaGua implements Quack {
@Override
public void quack() {System.out.println("呱呱叫");
}
}
吱吱叫实现类
public class QuackZhiZhi implements Quack {
@Override
public void quack() {System.out.println("吱吱叫");
}
}
不会叫实现类
public class QuackNoWay implements Quack {
@Override
public void quack() {System.out.println("不会叫");
}
}
3.3 鸭子类的实现
定义鸭子抽象类
public abstract class Duck {
protected Fly fly;
protected Quack quack;
public void swim() {System.out.println("正在游泳...");
}
public abstract void display();
public Fly getFly() {return fly;}
public Quack getQuack() {return quack;}
}
野鸭实现类
public class MallardDuck extends Duck {
// 野鸭用翅膀航行,呱呱叫
public MallardDuck() {this.fly = new FlyWithWings();
this.quack = new QuackGuaGua();}
@Override
public void display() {System.out.println("外观是绿头鸭");
}
}
红头鸭实现类
public class RedheadDuck extends Duck {
// 红头鸭用翅膀航行,呱呱叫
public RedheadDuck() {this.fly = new FlyWithWings();
this.quack = new QuackGuaGua();}
@Override
public void display() {System.out.println("外观是红头鸭");
}
}
橡皮鸭实现类
public class RubberDuck extends Duck {
// 橡皮鸭不会航行,吱吱叫
public RubberDuck() {this.fly = new FlyNoWay();
this.quack = new QuackZhiZhi();}
@Override
public void display() {System.out.println("外观是橡皮鸭");
}
}
钓饵鸭实现类
public class DecoyDuck extends Duck {
// 钓饵鸭不会航行,也不会叫
public DecoyDuck() {this.fly = new FlyNoWay();
this.quack = new QuackNoWay();}
@Override
public void display() {System.out.println("外观是钓饵鸭");
}
}
3.4 测试
编写简略测试类
public class Test {public static void main(String[] args) {MallardDuck mallardDuck = new MallardDuck();
mallardDuck.display();
mallardDuck.swim();
mallardDuck.getFly().fly();
mallardDuck.getQuack().quack();
System.out.println("-------------------");
DecoyDuck decoyDuck = new DecoyDuck();
decoyDuck.display();
decoyDuck.swim();
decoyDuck.getFly().fly();
decoyDuck.getQuack().quack();
}
}
输入后果
外观是绿头鸭
正在游泳...
用翅膀航行
呱呱叫
-------------------
外观是钓饵鸭
正在游泳...
不会航行
不会叫
4. 残缺代码
残缺代码请拜访我的 Github,若对你有帮忙,欢送给个 Star,谢谢!
https://github.com/gozhuyingl…
5. 参考
- 《Head First 设计模式》
- 《设计模式:可复用面向对象软件的根底》
举荐浏览
- 单例模式