Head First 设计模式之策略模式

本文通过一个模拟鸭子的游戏,介绍并实现了策略模式。策略模式允许在运行时选择算法,并且能够独立于使用这些算法的客户端。文章详细展示了如何通过接口和多态来实现策略模式,并解释了这种设计模式的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是策略模式

从简单的模拟鸭子做起

做一个模拟鸭子的游戏:SimDuck, 有各种鸭子,能游戏戏水能瓜瓜叫.

实现: 设计一个鸭子的超类

public abstract class Duck{
    public void quack(){
        // 嘎嘎, 超类实现
    }
    public void swim(){
        // 游泳, 超类实现
    }
    abstract void display();    // 不同鸭子外观不一样
}

各种鸭子子类实现

public class MallardDuck extends Duck{
    public void display(){
        // 绿头
    }
}
public class RedheadDuck extends Duck{
    public void display(){
        // 红头
    }
}

想让鸭子飞

方案一: 利用继承来提供Duck的行为
- 在超类Duck类中添加上fly()方法
- 但是, 子类不会飞的鸭子也继承了fly()方法
- 解决: 在子类中将fly()方法覆盖掉
- 缺点:
- 代码在多个子类重复
- 运行时行为不易改变
- 改变牵一发动全身
- 每当有新的子类鸭,就要检查是否覆盖fly()等方法

public abstract class Duck{
    ...
    public vode fly(){
        // 飞, 超类实现
    }
    ...
}

public class DecoyDuck extends Duck{
    ...
    public void fly(){
        // 覆盖, 不会飞
    }
    ...
}

方案二: 利用接口
- 将fly()取出来, 放进一个 [Flyable接口]中, 会飞的鸭子才实现此接口
- 解决了有些鸭子不会飞
- 缺点:
- 但是每个会飞的子类都要实现fly(),导致重复代码变多
- 并且无法复用

public interface Flyable{
    void fly();
}

public class MallardDuck extends Duck implements Flyable{
    ...
    public void fly(){
        // 飞, 子类实现
    }
    ...
}

设计原则: 找出应用中可能需要变化之处,把它们独立出来(封装起来,按需扩充),不要和那些不需要变化的代码混在一起

方案三: 取出Duck类中变化的部分 fly, 建立一组新类代表行为

设计原则: 针对接口编程,而不是针对实现编程
- 利用接口代表每个独立出来的行为, 如 FlyBehavior接口, fly行为的实现必须实现该接口
- 而鸭子类不负责独自实现fly行为了,由其fly行为类实现(实现的代码由鸭子类转到了行为类)
- 添加新的行为不会影响到既有的行为类,也不会影响使用到飞行行为的鸭子类

public interface FlyBehavior{
    void fly();
}


/**
下面是两个fly行为的不同实现类
*/

public class FlyWithWings implements FlyBehavior{
    void fly(){
        // 用翅膀飞, 实现了所有用翅膀飞的鸭子的的动作
    }
}

public class FlyNoWay implements FlyBehavior{
    void fly(){
        // 什么都不做,不会飞,实现了所有不会飞的鸭子的的动作
    }
}

整合鸭子的行为

public interface FlyBehavior{
    void fly();
}

public abstract class Duck implements FlyBehavior{
    FlyBehavior flyBehavior;    // 面向接口的实例变量,会利用多态方式在运行时引用正确的行为类型,每只鸭子都会引用实现FlyBehavior 接口的对象
    ...    
    public void performFly(){
        flyBehavior.fly();  // 不亲自处理飞行行为,而是委托给flyBehavior对象
    }
    ...
}   

public class FlyWithWings implements FlyBehavior{
    void fly(){
        // 用翅膀飞, 实现了所有用翅膀飞的鸭子的的动作
    }
}

public class RedheadDuck extends Duck{ 
    public RedheadDuck(){
        flyBehavior = new FlyWithWings();   // RedheadDuck继承Duck类,所以具有flyBehavior 实例变量  
    }
    ...
}


  • 想要进行fly行为, Duck对象只要叫flyBehavior对象去fly就行了, 这部分代码中, 不在乎FlyBehavior对象到底是什么,只关心该对象如何fly就行了.
    • 但是此时, 初始化变量flyBehavior 的做法不够弹性
    • 实例变量是一个接口类型,能够运行时,通过多态指定不同的FlyBehavior实现类给它
  • 在Duck类添加[setter方法],就可以在子类中调用设定鸭子的行为了

设计原则: 多用组合,少用继承
public abstract class Duck implements FlyBehavior{
    FlyBehavior flyBehavior;    // 面向接口的实例变量,会利用多态方式在运行时引用正确的行为类型,每只鸭子都会引用实现FlyBehavior 接口的对象
    ...
    // 新加setter方法
    public void setFlyBehavior(FlyBehavior fb){
        flyBehavior = fb;       //可以随时调用这个方法更改鸭子的行为
    }

    public void performFly(){
        flyBehavior.fly();  // 不亲自处理飞行行为,而是委托给flyBehavior对象
    }
    ...
}   

public class RedheadDuck extends Duck{ 
    public RedheadDuck(){
        flyBehavior = new FlyWithWings();   // RedheadDuck继承Duck类,所以具有flyBehavior 实例变量  
    }
    ...
}

public class Test{
    public static void main(String[] args){
        Duck red = new RedheadDuck();       // 针对接口编程,声明接口实例变量
        red.setFlyBehavior(new FlyWithWings());     //调用继承来的方法把翅膀飞行行为设定到红头鸭中
        red.performFly();
    }
}

策略模式

定义了算法族,分别封装起来,让它们之间互相替换, 让算法的变化独立于使用算法的客户

把鸭子的行为当成一族算法

Java实现代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值