MATLAB使いのハード屋のために教えてやるか、"デザインパターン"ってやつをよ……

https://www.amazon.co.jp/gp/product/B09HK66P5X/

↑の本の例と

https://www.techscore.com/tech/DesignPattern/

↑の例をMATLABで書き直したようなやつです。

あえてどういう意味なのか書かないのでちゃんと本を買ったり参考文献の解説を見てください。

# Iterator

```Matlab:Main.m
function Main
    clc;
    bookshelf = BookShelf();                                       % 本棚を作成
    bookshelf.appendBooks( Book('Around the World in 80 Days') );  % 本棚に本を収納
    bookshelf.appendBooks( Book('Bible') );                        % 本棚に本を収納
    bookshelf.appendBooks( Book('Cinderella') );                   % 本棚に本を収納
    bookshelf.appendBooks( Book('Daddy-Long-Legs') );              % 本棚に本を収納
    it = bookshelf.iterator();                                     % 本棚のイテレータを取得
    while it.hasNext()                                             % 次の本がある限り
        book = it.next();                                              % 次の本を取得
        disp(book.getName());                                          % 取得した本の名前を表示
    end
end
```

```:Main.mの実行結果
Around the World in 80 Days
Bible
Cinderella
Daddy-Long-Legs
```

```Matlab:Book.m
classdef Book < handle
    properties (GetAccess='private',SetAccess='private')
        name
    end
    methods
        function obj = Book(name)
            obj.name = name;
        end
        function name = getName(obj)   % 本の名前を返す
            name = obj.name;
        end
    end
end
```

```Matlab:BookShelf.m
classdef BookShelf < handle
    properties (GetAccess='private',SetAccess='private')
        books
    end
    methods
        function obj = BookShelf()
        end
        function appendBooks(obj,book)          % 本を収納する
            obj.books = [obj.books; book];
        end
        function num = getLength(obj)           % 収納されている本の数を返す
            num = length(obj.books);
        end
        function book = getBookAt(obj,index)    % index番目の本を返す
            book = obj.books(index);
        end
        function it = iterator(obj)             % イテレータを返す
            it = BookShelfIterator(obj);
        end
    end
end

function obj = BookShelfIterator(bookshelf)
    index = 1;    % 現在の取り出し番号
    obj.hasNext = @hasNext;
    function bool = hasNext                 % 次に取り出す本がまだあるか否かを真偽値で返す
        if index <= bookshelf.getLength()      % 現在の取り出し番号が本棚オブジェクトの収納数を超えていないか
            bool = true;                            % 超えていないなら真
        else
            bool = false;                           % 超えているなら偽
        end
    end
    obj.next = @next;
    function book = next                    % 次の本を取り出す
        book = bookshelf.getBookAt(index);     % 取り出し番号に対応する本を本棚から取り出す
        index = index + 1;                     % 取り出し番号を増やす
    end
end
```

# Composite

```Matlab:Main.m
function Main
    clc;
    
    dir1  = Directory('dir1');    % ディレクトリ dir1 の作成
    
    dir1.add(File('file1'));      % ファイル file1 を作成して dir1 に保存
    
    dir2  = Directory('dir2');    % ディレクトリ dir2 の作成
    
    dir2.add(File('file2'));      % ファイル file2 を作成して dir2 に保存
    dir2.add(File('file3'));      % ファイル file3 を作成して dir2 に保存
    
    dir1.add(dir2);               % dir1 に dir2 を保存
    dir1.add(File('file4'));      % ファイル file4 を作成して dir1 に保存
    
    dir1.remove();                % dir1 の削除
end
```

```Matlab:Main.mの結果
removed file1
removed file2
removed file3
removed dir2
removed file4
removed dir1
```

```Matlab:IDirectoryEntry.m
classdef IDirectoryEntry < handle
    methods (Abstract=true)
        remove(obj)
    end
end
```

```Matlab:Directory.m
classdef Directory < IDirectoryEntry
    properties (SetAccess='private',GetAccess='private')
        list
        name
    end
    methods
        function obj = Directory(name)
            obj.name = name;
            obj.list = [];
        end
        function add(obj, iDirectoryEntry)
            obj.list = [obj.list; {iDirectoryEntry}];
        end
        function remove(obj)
            for i = 1 : size(obj.list,1)
                obj.list{i}.remove();
            end
            fprintf('removed %s\n',obj.name);
        end
    end
end
```

```Matlab:File.m
classdef File < IDirectoryEntry
    properties (SetAccess='private',GetAccess='private')
        name
    end
    methods
        function obj = File(name)
            obj.name = name;
        end
        function remove(obj)
            fprintf('removed %s\n',obj.name);
        end
    end
end
```

# Factory

```Matlab:Main.m
function Main
    clc;
    factory = MembersIDFactory();
    members = [];
    members = [members; factory.getMembers('John')];
    members = [members; factory.getMembers('Jane')];
    members = [members; factory.getMembers('Daniel')];
    members = [members; factory.getMembers('Eve')];
    for i = 1 : length(members)
        members(i).dispNameAndID();
    end
end
```

```Matlab:結果
NAME: John   ID: 1
NAME: Jane   ID: 2
NAME: Daniel ID: 3
NAME: Eve    ID: 4
```

```Matlab:MembersIDFactory.m
classdef MembersIDFactory < handle
    properties (SetAccess='private',GetAccess='private')
        id
    end
    methods
        function obj = MembersIDFactory
            obj.id = 1;
        end
        function member = getMembers(obj,name)
            member = Members(name,obj.id);
            obj.id = obj.id + 1;
        end
    end
end

function obj = Members(name,id)
    obj.dispNameAndId = @dispNameAndId;
    function dispNameAndId
        fprintf('NAME: %s \t ID: %d \n',name,id);
    end
end
```

# Strategy

```Matlab:Main.m
function Main
    clc;
    human1 = Human('Yamada',180,25);            % 人物1号(山田さん,180cm,25歳)を作成
    human2 = Human('Tanaka',160,30);            % 人物2号(田中さん,160cm,30歳)を作成
    judger = Judger();                          % 審判を作成
    judger.setComparator(AgeComparator());      % 審判に具体的な審査基準を伝えておく
    judger.compare(human1,human2);              % 審判に二人の人物の比較をお願いする
    judger.setComparator(HeightComparator());   % 審判に新しい審査基準を伝えておく
    judger.compare(human1,human2);              % 審判に二人の人物の比較をお願いする
end
```

```:Main.mの実行結果
Yamada is Younger than Tanaka.
Yamada is higher than Tanaka.
```

```Matlab:Human.m
classdef Human < handle
    properties(SetAccess='private',GetAccess='private')
        name       % 名前
        height     % 身長
        age        % 年齢
    end
    methods
        function obj = Human(name, height, age)
            obj.name   = name;     % 名前の設定
            obj.height = height;   % 身長の設定
            obj.age    = age;      % 年齢の設定
        end
       function ret = getName(obj)   % 名前を返す
           ret = obj.name;
       end
       function ret = getHeight(obj) % 身長を返す
           ret = obj.height;
       end
       function ret = getAge(obj)    % 年齢を返す
           ret = obj.age;
       end
    end
end
```

```Matlab:Judger.m
classdef Judger < handle
    properties(SetAccess='private',GetAccess='private')
        comparator    % 審査基準
    end
    methods
        function obj = Judger()
        end
        function setComparator(obj,new_comparator)    % 新しい審査基準の設定
           obj.comparator = new_comparator;
        end
        function compare(obj,h1,h2)                   % 与えられた人物二人を比較する
           obj.comparator.compare(h1,h2);                 % 現在持っている審査基準で比較する
        end
    end
end
```

```Matlab:AbstractComparator.m
classdef AbstractComparator < handle
    methods (Abstract=true)          % 抽象的なメソッドの定義
        compare(h1, h2)                  % 人物二人を比較する
    end
end
```

```Matlab:AgeComparator.m
classdef AgeComparator < AbstractComparator        % AbstractComparatorを継承
    methods
        function obj = AgeComparator()
        end
        function compare(obj,h1,h2)                % 引数として渡された人物二人を年齢で審査する
            if     h1.getAge() > h2.getAge()
               fprintf('%s is Older than %s.\n',    h1.getName(), h2.getName());
            elseif h1.getAge() == h2.getAge()
               fprintf('%s and %s has same Age.\n', h1.getName(), h2.getName());
            else
               fprintf('%s is Younger than %s.\n',  h1.getName(), h2.getName());
            end
        end
    end
end
```

```Matlab:HeightComparator.m
classdef HeightComparator < AbstractComparator     % AbstractComparatorを継承
    methods
        function obj = HeightComparator()
        end
        function compare(obj,h1,h2)                % 引数として渡された人物二人を身長で審査する
            if     h1.getHeight() > h2.getHeight()
               fprintf('%s is higher than %s.\n',      h1.getName(), h2.getName());
            elseif h1.getHeight() == h2.getHeight()
               fprintf('%s and %s has same height.\n', h1.getName(), h2.getName());
            else
               fprintf('%s is shorter than %s.\n',     h1.getName(), h2.getName());
            end
        end
    end
end
```

# Observer

```Matlab:Main.m
function Main
    clc;
    generator = RandomNumberGenerator();    % 乱数発生機
    observer1 = DigitObserver();            % 観測者（乱数をデジタル表記で報告）
    observer2 = GraphObserver();            % 観測者（乱数をグラフ表記で報告）
    generator.addObserver(observer1);       % 観測者を乱数発生機に登録
    generator.addObserver(observer2);       % 観測者を乱数発生機に登録
    generator.execute();                    % 乱数を発生
end
```

```:Main.mの実行結果
DigitObserver: 20
GraphObserver:********************
DigitObserver: 13
GraphObserver:*************
DigitObserver: 21
GraphObserver:*********************
DigitObserver: 5
GraphObserver:*****
DigitObserver: 7
GraphObserver:*******
DigitObserver: 48
GraphObserver:************************************************
DigitObserver: 48
GraphObserver:************************************************
DigitObserver: 29
GraphObserver:*****************************
DigitObserver: 3
GraphObserver:***
DigitObserver: 12
GraphObserver:************
DigitObserver: 18
GraphObserver:******************
DigitObserver: 42
GraphObserver:******************************************
DigitObserver: 1
GraphObserver:*
DigitObserver: 3
GraphObserver:***
DigitObserver: 9
GraphObserver:*********
DigitObserver: 33
GraphObserver:*********************************
DigitObserver: 37
GraphObserver:*************************************
DigitObserver: 33
GraphObserver:*********************************
DigitObserver: 23
GraphObserver:***********************
DigitObserver: 28
GraphObserver:****************************
```

```Matlab:Observer.m
classdef Observer < handle
    methods
        function obj = Observer()
        end
    end
    methods(Abstract=true)
        update(obj,generator)
    end
end
```

```Matlab:DigitObserver.m
classdef DigitObserver < Observer
    methods
        function obj = DigitObserver()
        end
        function update(obj,generator)
            fprintf(['DigitObserver: ' num2str(generator.getNumber()) '\n']);
        end
    end
end
```

```Matlab:GraphObserver.m
classdef GraphObserver < Observer
    methods
        function obj = GraphObserver()
        end
        function update(obj,generator)
            fprintf('GraphObserver:');
            for i = 1 : generator.getNumber()
                fprintf('*');
            end
            fprintf('\n');
        end
    end
end
```

```Matlab:NumberGenerator.m
classdef NumberGenerator < handle
    properties(SetAccess='protected',GetAccess='protected')
        observers
    end
    methods
        function obj = NumberGenerator()
        end
        function addObserver(obj,observer)
            obj.observers = [obj.observers {observer}];
        end
        function deleteObserver(obj,observer)
            obj.observers(obj.ovservers == observer) = [];
        end
    end
    methods (Access='protected')
        function notifyObservers(obj)
            for i = 1 : length(obj.observers)
                obj.observers{i}.update(obj);
            end
        end
    end
    methods(Abstract=true)
        ret = getNumber(obj)
        execute(obj)
    end
end
```

```Matlab:RandomNumberGenerator.m
classdef RandomNumberGenerator < NumberGenerator
    properties(SetAccess='protected',GetAccess='protected')
        number
    end
    methods
        function obj = RandomNumberGenerator()
        end
        function ret = getNumber(obj)
            ret = obj.number;
        end
        function execute(obj)
            for i = 1 : 20
                obj.number = ceil(rand(1)*50);
                notifyObservers(obj);
                pause(0.33);
            end
        end
    end
end
```