什么是策略模式?
策略模式定义了算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户
设计原则
- 找出变化之处,把它们独立出来
- 针对接口编程,而不是针对实现编程
- 多用组合,少用继承
模拟鸭子游戏
SimUDuck,游戏中会出现各种鸭子,一边游泳戏水,一边呱呱叫。
使用面向对象的设计模式:设计鸭子的超类BaseDuck,并让各种鸭子继承此超类
public abstract class BaseDuck {
abstract void display();
}
野鸭子MallardDuck:
public class MallardDuck extends BaseDuck {
void display() {
// 我是绿头鸭
}
...
}
红头鸭子RedheadDuck:
public class RedheadDuck extends BaseDuck {
void display() {
// 我是红头鸭子
}
...
}
现在我们的让鸭子能飞
- 方案一:父类增加
public abstract class BaseDuck {
abstract void display();
public void fly() {
// 飞行,可复用
};
}
问题:并不是所有的鸭子都能飞
- 方案二:继承
public abstract class BaseDuck {
abstract void display();
abstract void fly();
}
问题:每个子类都需要重写, 无法复用
public class RubberDuck extends BaseDuck {
void display() {
// 橡皮鸭
}
void fly() {
// 覆盖,什么都不做
}
}
public class DecoyDuck extends BaseDuck {
void display() {
// 诱饵鸭
}
void fly() {
// 覆盖,什么都不做
}
}
- 方案三:利用接口,同时增加鸭子叫接口
public interface Flyable {
fly();
}
public interface Quackable {
quack();
}
public MallardDuck extends BaseDuck implements Flyable, Quackable {
void fly() {
// 翅膀飞行
}
void quack() {
// 呱呱叫
}
}
问题:重复的代码越来越多
解决方案
使用设计原则一:封装变化
使用设计原则二:针对接口编程
- 抽取变化部分为接口
public interface FlyBehavior {
void fly();
}
public interface QuackBehavior {
void quack();
}
- 把每个行为实现单独作为一个类
public class FlyWithWings implments FlyBehavior {
void fly() {
// 使用翅膀飞行
}
}
public class FlyNoWay implments FlyBehavior {
void fly() {
// 什么都不做,不会飞!
}
}
public class Quack implments QuackBehavior {
void quack() {
// 鸭子呱呱叫
}
}
public class Squeak implments QuackBehavior {
void quack() {
// 橡皮鸭子吱吱叫
}
}
public class MuteQuack implments QuackBehavior {
void quack() {
// 什么都不做,不会叫
}
}
- 从新定义鸭子超类
public abstract class Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
void display();
public void performFly(){
if (flyBehavior != null) {
flyBehavior.fly();
}
}
public void performQuack(){
if (quackBehavior != null) {
quackBehavior.quack();
}
}
}
- 定义鸭子的实体类
public class MallardDuck extends BaseQuack {
public MallardDuck() {
// 将鸭子的飞的行为和叫的行为,委托给行为类
flyBehavior = new FlyBehavior();
quackBehavior = new QuackBehavior();
}
void display() {
// 野鸭子
}
}
public class Test {
public static void main(String[] args){
Duck duck = new MallardDuck();
duck.performFly();
duck.performQuack();
}
}
问题:MallardDuck内部还是使用了针对实现编程
解决方案
- 在超类鸭子中增加两个方法
public abstract class Duck {
...
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
}
- 动态设置行为
public class Test {
public static void main(String[] args){
Duck duck = new MallardDuck();
duck.setFlyBehavior(new FlyWithWings());
duck.setQuackBehavior(new Quack());
duck.performFly();
duck.performQuack();
}
}