「ヘッドファーストデザインパターン」の研究ノート - コマンドモード

コマンドモード - カプセル化されたメソッド呼び出し、我々は操作ブロックを形成するパッケージ化することができます。だから私たちはラッピング方法を終えることができることを知って、物事が行われる方法を気にする必要はありません。この操作オブジェクトを呼び出します。

ケース

家電・オートメーションリモートコントロールAPIを作ります。このスロットは、7つのプログラマブルリモコン(それぞれが異なる家電機器に割り当てられてもよい)を有し、各スロットは、対応するスイッチボタンを有します。このリモートコントローラは、さらに、全体元に戻すボタンを含みます。

まず、我々は、すべてのコマンドオブジェクトが同じインターフェイスを達成するための方法を含んでいるようにする必要があります。

public interface Command {
    public void execute();
}

次に、放電ランプ、このオブジェクトを含むランプ、並びに指令を達成するための方法を開くためのコマンドを作成します。我々はexecute()メソッドを呼び出して、ランタン適切なアクション。

public class LightOnCommand implements Command {
    Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.on();
    }
}

ランプコード。

public class Light {
    public void on() {
        System.out.println("Light on");
    }
}

今、オブジェクトランプ、およびコマンドオブジェクトも作成し、我々は必要なものをしていますか?誰でも思いつきそう、リモートオブジェクトああ!

public class SimpleRemoteControl {
    Command slot;

    public SimpleRemoteControl() {}

    public void setCommand(Command command) {
        this.slot = command;
    }

    public void buttonWasPressed() {
        slot.execute();
    }
}

これは、コマンド属性、設定コマンドセッターメソッドを含む、オブジェクトの単純なリモコンであり、()buttonWasPressedリモコンボタンプレス法を示します。私たちは、ボタンを押しますときに、あなただけのこのメソッドを呼び出すことができます。

今、簡単なテストでの見てみましょう。

public class RemoteControlTest {
    public static void main(String[] args) {
        SimpleRemoteControl control = new SimpleRemoteControl();
        Light light = new Light();
        LightOnCommand lightOnCommand = new LightOnCommand(light);

        control.setCommand(lightOnCommand);
        control.buttonWasPressed();
    }
}

まず、私たちは、リモートオブジェクトを作成し、オブジェクトのライトを作成し、コマンドオブジェクトのライトをオンにし、コマンドオブジェクトは、ボタンを押すのメソッドInvoke、リモートオブジェクトに設定されています。あなたは、コンソール出力が表示されますLight on

ここでは、そのクラスを高め、新しいユニットは、ドアとして、動作する必要が追加して、より多くの次の繰り返し操作よりも、実際は何もして、APIリモコンの一部を達成している、そしてクラスコマンドのコマンドインタフェースで実現追加し、その後、setCommand(コマンドコマンド)渡すオブジェクト。

異なる要求、キューまたはその他のオブジェクトを使用するオブジェクトにカプセル化されたコマンドモード「リクエスト」、パラメータ化ログです。コマンドモードも取り消し可能操作がサポートされています。

私たちは、この定義では、慎重に見て、特定の受信者に一連のアクションを結合することにより、コマンドオブジェクトがその要求にパッケージ化されたので、私たちは、コマンドオブジェクトと受信オブジェクトだけでなく、パッケージの操作、およびオブジェクトが必要です露出のみexecute()メソッドは、このメソッドが呼び出されたときに、これらのアクションが実行され、呼び出し側はちょうど私たちはexecute()メソッドを呼び出すために他に何のニーズに完了しなければならないことを知っているアクション、受信者だった知りません。

Commandオブジェクトは、仲介と等価である当事者は家を提供し、彼は目的は達した家を買ったので、他にのみ、お金を提供しています。コマンド・インタフェース、調停に登録された家の売り手を実装し、その後、洗浄後の一連のステップを経て、装飾、唯一知っている必要があり、売り手、私は中間の呼び出しにexecute()メソッドを払って家を取得することができ、その目的を完了するために、家を買う仲介。

しかし、我々は単に一つだけのボタンで簡単なリモートコントロールを定義し、我々は今、そのベースでマルチボタンリモコンを実現します。

public class RemoteControl {
    ArrayList<Command> onCommands;
    ArrayList<Command> offCommands;

    public RemoteControl() {
        this.onCommands = new ArrayList<>();
        this.offCommands = new ArrayList<>();
    }

    public void setCommands(Command onCommand, Command offCommand) {
        this.onCommands.add(onCommand);
        this.offCommands.add(offCommand);
    }

    public void onButtonWasPushed(int slot) {
        this.onCommands.get(slot).execute();
    }

    public void offButtonWasPushed(int slot) {
        this.offCommands.get(slot).execute();
    }
}

一貫性指数を確保するために、それぞれ開口オフコマンドとコマンドオブジェクトのセットを受信し、その後、同時に2つのコマンドを設定します。追加オブジェクトクラス()メソッドオフ、オブジェクトが閉じられ又は回収手段を示します。

public class Light {
    public void on() {
        System.out.println("Light on");
    }

    public void off() {
        System.out.println("Light off");
    }
}

そして、表現のライトをオフにする新しいコマンドを作成します。

public class LightOffCommand implements Command {
    Light light;

    public LightOffCommand(Light light) {
        this.light = light;
    }
    @Override
    public void execute() {
        light.off();
    }
}

最後に、ビューの試験クラスリモートオブジェクトを作成し、制御対象部材を作成するためには、オブジェクトは、スイッチコマンドは、リモートオブジェクトに設定コマンドオブジェクト、呼び出しボタンを示し、最後に実行作成します。

public class RemoteControlTest {
    public static void main(String[] args) {
        RemoteControl remoteControl = new RemoteControl();

        Light light = new Light();
        GarageDoor garageDoor = new GarageDoor();

        LightOnCommand lightOnCommand = new LightOnCommand(light);
        LightOffCommand lightOffCommand = new LightOffCommand(light);
        GarageDoorOpenCommand garageDoorOpenCommand = new GarageDoorOpenCommand(garageDoor);
        GarageDoorCloseCommand garageDoorCloseCommand = new GarageDoorCloseCommand(garageDoor);

        remoteControl.setCommands(lightOnCommand, lightOffCommand);
        remoteControl.setCommands(garageDoorOpenCommand, garageDoorCloseCommand);

        remoteControl.onButtonWasPushed(1);
        remoteControl.offButtonWasPushed(1);
        remoteControl.onButtonWasPushed(2);
        remoteControl.offButtonWasPushed(2);
    }
}

あなたは()メソッドはlight.on(IS)ターンオンコマンド、実行など、否定動作に相当する元に戻す元に戻す()メソッド、およびアンドゥ()が実行されるlight.off()メソッドを追加してもよいです。

今、私たちは、修正方法に()コマンドインターフェースを元に戻す追加します。

public interface Command {
    public void execute();
    public void undo();
}

その後、修正されたコマンドの実装クラス、LightOnCommand、LightOffCommand。

public class LightOnCommand implements Command {
    Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.on();
    }

    @Override
    public void undo() {
        light.off();
    }
}

public class LightOffCommand implements Command {
    Light light;

    public LightOffCommand(Light light) {
        this.light = light;
    }
    @Override
    public void execute() {
        light.off();
    }

    @Override
    public void undo() {
        light.on();
    }
}

今、私たちは、リモートコントロールの手順を変更する必要がリモコン型RemoteControlWithUndoクラスを見てみましょう。

public class RemoteControlWithUndo {
    Command[] onCommands;
    Command[] offCommands;
    Command undoCommand;

    public RemoteControlWithUndo() {
        onCommands = new Command[7];
        offCommands = new Command[7];
        NoCommand noCommand = new NoCommand();

        for (int i = 0; i < onCommands.length; i++) {
            onCommands[i] = noCommand;
            offCommands[i] = noCommand;
        }
        undoCommand = noCommand;
    }

    public void setCommands(int slot, Command onCommand, Command offCommand) {
        onCommands[slot] = onCommand;
        offCommands[slot] = offCommand;
    }

    public void onButtonWasPushed(int slot) {
        onCommands[slot].execute();
        undoCommand = onCommands[slot];
    }

    public void offButtonWasPushed(int slot) {
        offCommands[slot].execute();
        undoCommand = offCommands[slot];
    }

    public void undoButtonWasPushed() {
        undoCommand.undo();
    }
}

私たちは、コマンド属性undoCommandを加え、次いで空の初期化するコマンドを指定してきた、私が代わりに、コマンドの配列のコマンドセットを使用して、この時間は、コマンドが呼び出されたときにエラーを防止するために、我々は全体の配列が各要素は、コマンドが表示されますを空に初期化されている必要があります。ボタンが押されたメソッド呼び出しは、コマンドにundoCommandに設定されているたびに、ちょうど私たち()メソッドはundoButtonWasPushedでコマンドundoCommand.undo()によって取り消すことができるように、呼び出します。

今、時間のテストがあります。

public class RemoteControlWithUndoTest {
    public static void main(String[] args) {
        RemoteControlWithUndo remoteControlWithUndo = new RemoteControlWithUndo();

        Light light = new Light();

        LightOnCommand lightOnCommand = new LightOnCommand(light);
        LightOffCommand lightOffCommand = new LightOffCommand(light);

        remoteControlWithUndo.setCommands(0, lightOnCommand, lightOffCommand);

        remoteControlWithUndo.onButtonWasPushed(0);
        remoteControlWithUndo.offButtonWasPushed(0);
        remoteControlWithUndo.undoButtonWasPushed();
        remoteControlWithUndo.offButtonWasPushed(0);
        remoteControlWithUndo.undoButtonWasPushed();
    }
}

リモートコントロール、ターゲットライトを作成したら、私たちの小さなリモコンが私たちの目標を達成しているテストし、元に戻す方法オフ、コマンド、コマンドセット、上の通話ボタンを作成するために電気を消すライトをオン。

今、我々はまた、改善することができるアンドゥを実装するために使用状態を、我々は今、このようなファン速度設定、高、中、低、オフのように、状態によって失効の値を実現します。今度はコードを見てみましょう。

public class CeilingFan {
    public static final int HIGH = 3;
    public static final int MEDIUM = 2;
    public static final int LOW = 1;
    public static final int OFF = 0;
    String location;
    int speed;

    public CeilingFan(String location) {
        this.location = location;
        speed = OFF;
    }

    /**
     * 设置高转速
     */
    public void high() {
        speed = HIGH;
        System.out.println("high");
    }

    /**
     * 设置中转速
     */
    public void medium() {
        speed = MEDIUM;
        System.out.println("medium");
    }

    /**
     * 设置低转速
     */
    public void low() {
        speed = LOW;
        System.out.println("low");
    }

    /**
     * 关闭吊扇
     */
    public void off() {
        speed = OFF;
        System.out.println("off");
    }

    public int getSpeed() {
        return speed;
    }
}

四つの状態が天井閉じファン、低、中、高スピードがありますので、スピードを切り替えるための4つの方法は、現在の速度、高、中で次のような外観と近いコマンドクラスを取得する方法があるがあります。

public class CeilingFanHighCommand implements Command {
    CeilingFan ceilingFan;
    int prevSpeed;

    public CeilingFanHighCommand(CeilingFan ceilingFan) {
        this.ceilingFan = ceilingFan;
    }

    @Override
    public void execute() {
        prevSpeed = ceilingFan.getSpeed();
        ceilingFan.high();
    }

    @Override
    public void undo() {
        if (prevSpeed == CeilingFan.HIGH) {
            ceilingFan.high();
        } else if (prevSpeed == CeilingFan.MEDIUM) {
            ceilingFan.medium();
        } else if (prevSpeed == CeilingFan.LOW) {
            ceilingFan.low();
        } else if (prevSpeed == CeilingFan.OFF) {
            ceilingFan.off();
        }
    }
}

public class CeilingFanMediumCommand implements Command {
    CeilingFan ceilingFan;
    int prevSpeed;

    public CeilingFanMediumCommand(CeilingFan ceilingFan) {
        this.ceilingFan = ceilingFan;
    }

    @Override
    public void execute() {
        prevSpeed = ceilingFan.getSpeed();
        ceilingFan.medium();
    }

    @Override
    public void undo() {
        if (prevSpeed == CeilingFan.HIGH) {
            ceilingFan.high();
        } else if (prevSpeed == CeilingFan.MEDIUM) {
            ceilingFan.medium();
        } else if (prevSpeed == CeilingFan.LOW) {
            ceilingFan.low();
        } else if (prevSpeed == CeilingFan.OFF) {
            ceilingFan.off();
        }
    }
}

public class CeilingFanOffCommand implements Command {
    CeilingFan ceilingFan;
    int prevSpeed;

    public CeilingFanOffCommand(CeilingFan ceilingFan) {
        this.ceilingFan = ceilingFan;
    }

    @Override
    public void execute() {
        prevSpeed = ceilingFan.getSpeed();
        ceilingFan.off();
    }

    @Override
    public void undo() {
        if (prevSpeed == CeilingFan.HIGH) {
            ceilingFan.high();
        } else if (prevSpeed == CeilingFan.MEDIUM) {
            ceilingFan.medium();
        } else if (prevSpeed == CeilingFan.LOW) {
            ceilingFan.low();
        } else if (prevSpeed == CeilingFan.OFF) {
            ceilingFan.off();
        }
    }
}

シーリングファンが天井扇風機の状態変化は、状態を受信した後、元に戻す()メソッドがある場合、受信状態前の状態を持っている、prevSpeedの状態によって決定される順序を取り消します。

Testクラス、および前のステップと同じで、あなたがテストし、修正することができます。

public class RemoteTest {
    public static void main(String[] args) {
        RemoteControlWithUndo remoteControlWithUndo = new RemoteControlWithUndo();

        CeilingFan ceilingFan = new CeilingFan("Room");

        CeilingFanMediumCommand ceilingFanMediumCommand = new CeilingFanMediumCommand(ceilingFan);
        CeilingFanHighCommand ceilingFanHighCommand = new CeilingFanHighCommand(ceilingFan);
        CeilingFanOffCommand ceilingFanOffCommand = new CeilingFanOffCommand(ceilingFan);

        remoteControlWithUndo.setCommands(0, ceilingFanHighCommand, ceilingFanOffCommand);
        remoteControlWithUndo.setCommands(1, ceilingFanMediumCommand, ceilingFanOffCommand);

        remoteControlWithUndo.onButtonWasPushed(0);
        remoteControlWithUndo.offButtonWasPushed(0);
        remoteControlWithUndo.undoButtonWasPushed();

        remoteControlWithUndo.onButtonWasPushed(1);
        remoteControlWithUndo.undoButtonWasPushed();
    }
}

このようにして、我々は国家によって失効を達成完了です。私たちが見て次にマクロコマンド、実際には非常に簡単です、修正するために()メソッドを実行する方法が可能()を実行するために、1つの呼び出しによって、当社のonCommands配列、1を通過することです。

全体のコマンドモードはあまりそれの、最後に来て、その後、定義を見直しました。

異なる要求、キューまたはその他のオブジェクトを使用するオブジェクトにカプセル化されたコマンドモード「リクエスト」、パラメータ化ログです。コマンドモードも取り消し可能操作がサポートされています。

公開された26元の記事 ウォンの賞賛2 ビュー2327

おすすめ

転載: blog.csdn.net/qq_42909545/article/details/104923590