MatlabでStatePattern

udemy(参考に記載)でC#のStatePatternを聴講し、普段使っているMatlabのAppDesignerに実装してみた。

# 仕様
On/Offボタン：Lowに遷移

Off以外のときに
Upボタン：Low→Middle→High→Low→…
Downボタン：High→Middle→Low→High→…
Maxボタン：Highに遷移
Minボタン：Lowに遷移

フォルダ直下のheater.txtにワット数を出力する。

# Main GUI
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579192/1d1f2c25-4d44-eff7-42a2-982916aa9849.png)

```Matlab:Main.mlapp
properties (Access = private)
    context_
end
    
methods (Access = private)
    function context_StateChanged(app, src, evnt)
        app.lbl_State.Text = app.context_.GetText();
    end
end

% Callbacks that handle component events
methods (Access = private)
    % initialize
    function startupFcn(app)
        movegui(app.UIFigure, 'center');
        app.context_ = Context;
        addlistener(app.context_, 'StateChanged', @app.context_StateChanged);

        app.context_StateChanged();
    end

    % On/Offボタンクリック時のコールバック
    function pb_OnOffButtonPushed(app, event)
        app.context_.OnOff();
    end

    % Upボタンクリック時のコールバック
    function pb_UpButtonPushed(app, event)
        app.context_.Up();
    end

    % Downボタンクリック時のコールバック
    function pb_DownButtonPushed(app, event)
        app.context_.Down();
    end

    % Maxボタンクリック時のコールバック
    function pb_MaxButtonPushed(app, event)
        app.context_.Max();
    end

    % Minボタンクリック時のコールバック
    function pb_MinButtonPushed(app, event)
        app.context_.Min();
    end
end
```

# 各Class

## 各State

### Abstract (Interface)
```Matlab:IState.m
classdef IState < handle
    properties
    end
    methods (Abstract = true)
        UpState
        DownState
        OnOffState
        GetText
        GetCommand
    end
    methods (Static, Sealed = true)
        function OffWarning()
            warndlg('まずはOnにしてください')
        end
    end
end
```

### 実装
```Matlab:OffState.m
classdef OffState < IState
    properties
    end
    methods (Access = public, Sealed = true)
        function UpState(this, context)
            this.OffWarning();
            return;
        end
        function DownState(this, context)
            this.OffWarning();
            return;
        end
        function OnOffState(this, context)
            context.ChangeState(LowState);
        end
        function out = GetCommand(this)
            % なにか処理を行う。
            out = {'Off'; '0W'};
        end
        function out = GetText(this)
            out = 'Off';
        end
    end
    methods (Static)
    end
end
```

```Matlab:LowState.m
classdef LowState < IState
    properties
    end
    methods (Access = public, Sealed = true)
        function UpState(this, context)
            context.ChangeState(MiddleState);
        end
        function DownState(this, context)
            context.ChangeState(HighState);
        end
        function OnOffState(this, context)
            context.ChangeState(OffState);
        end
        function out = GetCommand(this)
            % なにか処理を行う。
            out = {'Low'; '500W'};
        end
        function out = GetText(this)
            out = 'Low';
        end
    end
    methods (Static)
    end
end
```

```Matlab:MiddleState.m
classdef MiddleState < IState
    properties
    end
    methods (Access = public, Sealed = true)
        function UpState(this, context)
            context.ChangeState(HighState);
        end
        function DownState(this, context)
            context.ChangeState(LowState);
        end
        function OnOffState(this, context)
            context.ChangeState(OffState);
        end
        function out = GetCommand(this)
            % なにか処理を行う。
            out = {'Middle'; '1000W'};
        end
        function out = GetText(this)
            out = 'Middle';
        end
    end
    methods (Static)
    end
end
```

```Matlab:HighState.m
classdef HighState < IState
    properties
    end
    methods (Access = public, Sealed = true)
        function UpState(this, context)
            context.ChangeState(LowState);
        end
        function DownState(this, context)
            context.ChangeState(MiddleState);
        end
        function OnOffState(this, context)
            context.ChangeState(OffState);
        end
        function out = GetCommand(this)
            % なにか処理を行う。
            out = {'High'; '1500W'};
        end
        function out = GetText(this)
            out = 'High';
        end
    end
    methods (Static)
    end
end
```

## 現在の状態Class
```Matlab:Context.m
classdef Context < handle
    properties (SetAccess = private, GetAccess = private)
        state_
    end
    events
        StateChanged
    end
    methods (Access = public, Sealed = true)
        function this = Context
            this.state_ = OffState;
            this.Send();
        end
        function Up(this)
            this.state_.UpState(this);
            this.Send();
        end
        function Down(this)
            this.state_.DownState(this);
            this.Send();
        end
        function OnOff(this)
            this.state_.OnOffState(this);
            this.Send();
        end
        function Max(this)
            if isequal(this.state_, OffState)
                this.state_.OffWarning();
                return
            end
            this.ChangeState(HighState);
            this.Send();
        end
        function Min(this)
            if isequal(this.state_, OffState)
                this.state_.OffWarning();
                return
            end
            this.ChangeState(LowState);
            this.Send();
        end
        function out = GetText(this)
            out = this.state_.GetText();
        end
        function this = ChangeState(this, IState)
            this.state_ = IState;
            notify(this, 'StateChanged');
        end
    end
    methods (Access = private)
        function Send(this)
            path = 'heater.txt';
            writecell(this.state_.GetCommand(), path);
        end
    end
end
```

# 参考
udemyのピーコックアンダーソン氏の講義
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579192/8ec5e655-cada-3758-5f48-fdd4293b2058.png)

[MathWorks: イベントとリスナーの構文](https://jp.mathworks.com/help/matlab/matlab_oop/events-and-listeners-syntax-and-techniques.html)
[MathWorks: リスナー コールバックの構文](https://jp.mathworks.com/help/matlab/matlab_oop/listener-callback-functions.html)