策略模式 (键盘选好了吗?)

270 阅读4分钟

策略模式 (键盘选好了吗?)

最近为了打游戏买了一个青轴的键盘,为啥要买青轴的呢?原因就是喜欢青轴键盘敲起来那种噼里啪啦的声音 ,但是这种键盘只适合私人场合,在宿舍等公共场合就不要买这种了,不然就是:

自从用了青轴键盘之后,每次打游戏都仿佛有Buff加成一样,欢快的不得了!

但女朋友就不开心了,每天都得忍受噼里啪啦的噪音,女朋友不开心你还有好日子过,品,你仔细品,还不得主动跪键盘?

青轴的跪起来实在太疼了,受力面积还小,这不行啊!得想想办法,又去某宝买了一个专门用来跪的键盘,受力面积大,而且还不硬,舒服了!

好日子没过几天,公司加任务了,只能老老实实码代码了,码代码得有个安静的环境啊,青轴的肯定不行了,跪的键盘是专门用来跪的,只得换回原来的键盘了...

今天不是讲策略模式的吗,你讲键盘干嘛? 讲完了啊,上面选键盘就是策略模式啊! 啥!!!

那接下来我们看看策略模式是怎么定义的:

策略(Strategy)模式:策略模式也叫政策模式(Policy Pattern),其作用是针对一组算法,将每一个算法单独封装起来,让它们可以相互替换,策略模式使得算法可以在不影响客户端的情况下发生变化.

这不,上面我们上面的三个键盘不就是相当于封装了三个算法嘛,在不同的场景需要它们互相替换,那么该如何做到让它们可以相互替换了?简单,使用多态的形式不就可以了吗?实现同一个接口或继承同一个类,实际上我们也同样会这样做.

了解了概念以后,我们有必要看一下策略模式的简单类图:

  • 封装(Context)角色:也叫上下角色,起承上启下封装作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化,维护一个Strategy引用.
  • 抽象策略角色(Strategy):这是一个抽象角色,通常由一个接口或者抽象类实现,此角色给出所有具体策略类所需的接口.
  • 具体策略类(ConcreteStragety):封装了具体的算法和行为,实现了Strategy接口

现在是不是很清晰了,三个键盘就是具体的策略,它们需要实现一个抽象策略角色接口,然后使用封装角色封装它们的变化,代码实现:

//Strategy
public interface Keyboard {
    /**
     * 键盘用途
     */
    void use();
}

//青轴游戏键盘 concreteStrategy
public class GameKeyboard implements Keyboard {
    @Override
    public void use() {
        System.out.println("玩游戏~~~");
    }
}

//某宝买的跪键盘 concreteStrategy
public class KneelingKeyboard implements Keyboard{
    @Override
    public void use() {
        System.out.println("跪键盘~~~");
    }
}

//敲代码的老键盘 concreteStrategy
public class CodeKeyboard implements Keyboard {
    @Override
    public void use() {
        System.out.println("敲代码~~~");
    }
}

//封装对象
public class Context {
    //Strategy reference
    private  Keyboard keyboard;

    public Context(Keyboard keyboard) {
        this.keyboard = keyboard;
    }

    public void use(){
        keyboard.use();
    }
}

//客户端
public class Client {
    public static void main(String[] args){
        //打游戏 噼里啪啦
        Context game= new Context(new GameKeyboard());
        game.use();

        //女朋友生气 跪键盘
        Context kneeling = new Context(new KneelingKeyboard());
        kneeling.use();

        //码代码
        Context code = new Context(new CodeKeyboard());
        code.use();
    }
}

客户端的调用非常简单,只需要知道使用那个策略,然后放到封装对象中即可,策略模式就是这么简单.

什么时候使用策略模式:

  • 如果一个系统需要动态的在几种算法中选用一种
  • 一个系统的算法的具体行为不想让客户知道
  • 多个类只有算法或行为上稍有不同

接下我们看一下策略模式的优缺点:

优点:

  • 算法可以自由切换:只需要实现了抽象策略,它就可以通过封装对象进行切换,保证对外提供可自由切换的策略
  • 避免多重判断:如果不使用策略模式,将所有逻辑放在客户端,客户端通过条件选择语句决定使用哪一种算法,这样一来,客户端代码变得哪以维护,使用策略模式,可以将具体算法封装到具体策略类中,可以使用封装对象选择使用哪种策略
  • 扩展性良好:每次增加一个策略类,只需要实现抽象策略即可
  • 可以避免重复代码:重复代码可以向上提取

缺点:

  • 客户端必须知道所有的策略类,并自行决定使用哪一种策略类,这意味着客户端必须理解这些策略算法的区别,以便选择合适的策略,这一点与迪米特法则相违背.
  • 如果策略过多的话,会产生很多的策略类.