设计模式

策略模式(分离算法,选择实现)

2017-02-12  本文已影响41人  幺鹿

公告

如果您是第一次阅读我的设计模式系列文章,建议先阅读设计模式开篇,希望能得到您宝贵的建议。

前言

Alice这个购买机器人女友的事情闹的沸沸扬扬,Alice的爸爸实在不能同意Alice这样胡闹下去,于是Alice的爸爸就去了Alice家(他们平时不住在一起)。

无巧不巧的是那天正好Alice不在家,只有女友Samu在家。于是Alice的爸爸Samu开门表明身份是Alice的爸爸,可是Samu最终仍是拒绝了开门……最后Alice的爸爸在寒冷的北风中站了8个小时后,Alice回来后 Samu才开的门。

正文

Alice的爸爸Samu开开门,我是Alice的爸爸
Samu无法鉴定身份,抱歉无法为你开门。
Alice的爸爸:我出示我的身份证给你看,Samu。(出示了身份证)
Samu无法鉴定身份,抱歉无法为你开门。
Alice的爸爸:……(吐血中)
……(Alice回来了)
AliceSamu开开门。
Samu:欢迎回家,Alice
Alice的爸爸:……(吐血中)

程序员视角

现在要实现身份识别验证后开门的功能,起初Alice并没有把他爸爸的信息告知Samu,所以Samu无法为他开门。后面Alice允许Samu授予他爸爸开门的权限。

在本章中不将重心放在权限层级(如果要考虑权限相对复杂,可考虑享元模式),仅考虑如何识别身份后的分支操作 — — 开门或不开门

当然如果只是IF-ELSE自然是TOO YOUNG TOO SIMPLE

如何实现

策略模式本质:分离算法,选择实现。

参考状态模式 命令模式中的经验,单个命令或状态只处理其自身的逻辑。— — 职责单一原则

为了保证23个GOF都使用同一个GITHUB项目,所以计划23个GOF模式都会使用同一个场景“机器人”作为基础,所以故事之间会有一些关联。

延续前一篇文章“命令行模式”,本次要求能够接收开门命令,所以需要实现接口开门命令

定义开门命令

public class OpenDoorCommandImpl implements ICommand {

    private User user;
    private Machine machine;

    public OpenDoorCommandImpl(User user, Machine machine) {
        this.user = user;
        this.machine = machine;
    }

    @Override
    public void excute() {
        machine.getStrategy(user).operation();
    }
}

同时为了模拟机器人管理开门策略,所以在Machine中作了些许变更。

public class Machine {

    private String name;

    public Machine(String name) {
        this.name = name;
        System.out.println("创建了机器人 " + name);
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
   // 管理了所有的策略(这里是策略接口)
    private HashMap<User, IStrategy> map = new HashMap<>();

    public void configure(User user, IStrategy strategy) {
        map.put(user, strategy);
    }

    public IStrategy getStrategy(User user) {
        return map.get(user);
    }


    @Override
    public String toString() {
        return name;
    }

}

定义命令接收器

public class OpenDoorCommandReceiver {

    private CommandManager invoke = new CommandManager();
    private Machine machine;

    public OpenDoorCommandReceiver(Machine machine) {
        this.machine = machine;
        System.out.printf("机器人%s的接收功能正常开启%n", machine);
    }

    public void onReceive(String command, User user) {
        System.out.printf("机器人%s接收到指令:%s,%s%n", machine, command, user);
        invoke.invoke(new OpenDoorCommandImpl(user, machine));
    }
}

原先在调用播放歌曲命令时,使用适配器适配了String类型作为命令参数。在本例时,暂时不做适配器适配开门命令接口,下一篇文章会仔细描述适配器模式

定义策略的接口:

public interface IStrategy {

    void operation();
}

实现成功开门策略:

public class VerifySuccessStrategy implements IStrategy {
    @Override
    public void operation() {
        System.out.println("验证通过,已将门打开");
    }
}

实现失败开门策略:

public class VerifyFailStrategy implements IStrategy {
    @Override
    public void operation() {
        System.out.println("验证失败,无法为您开门");
    }
}

客户端调用测试

public class Client {

    public static void main(String[] args) {
        User alice = new User("Alice");
        User aliceParent = new User("Alice's Parent");


        Machine machine = new Machine("Samu");
        machine.configure(alice, new VerifySuccessStrategy());
        machine.configure(aliceParent, new VerifyFailStrategy());


        OpenDoorCommandReceiver receiver = new OpenDoorCommandReceiver(machine);
        System.out.println("++aliceParent++");
        receiver.onReceive("开门", aliceParent);
        System.out.println("--aliceParent--");
        System.out.println("++alice++");
        receiver.onReceive("开门", alice);
        System.out.println("--alice--");

    }
}

测试结果

创建了机器人 Samu
机器人Samu的接收功能正常开启
++aliceParent++
机器人Samu接收到指令:开门,com.bookbuf.gof23.User@1b6d3586
验证失败,无法为您开门
--aliceParent--
++alice++
机器人Samu接收到指令:开门,com.bookbuf.gof23.User@28d93b30
验证通过,已将门打开
--alice--

总结

策略模式的本质:分离算法,选择实现

策略模式类图

策略模式的优点

策略模式的缺点

在以下情况下可以使用策略模式:

上一篇下一篇

猜你喜欢

热点阅读