LoginSignup
24
23

More than 5 years have passed since last update.

なぜ書くか

MATLABで普段研究してる大学生なんですが、
コードをうだうだかき回すのキモいなって思って、
依存性は排除しつつもできるだけ使いまわせるように
MatlabでのOOPを試みてきました。
プログラミング歴まだ2年なので、色々試行錯誤してます。

Mathworks社の出しているリファレンスが残念ながら結構
わかりづらいのでここにまとめてみようと思います。

Matlabの雰囲気

Matlabってなんだよ…初めて聞くよ…??
って方のために、簡単に言語としてのイメージを伝えると、
Matlab = (Ruby+Python+Java)/3;
です。
オブジェクト指向で書けるしパッケージがあって、
でもクラスの書き方はRuby+Pythonで、、、
といった雰囲気です。

行列計算とグラフ出力が標準で組み込まれているため
統計解析を用いた研究などをする際に多く使われています。

目次

  • パッケージの作り方と呼び出し方
  • クラスの作り方
  • インスタンス化
  • オブジェクト配列の作り方
  • 申し訳程度に抽象クラスの作り方

パッケージの作り方と呼び出し方

名前空間が衝突しないようにパッケージで
階層を設けるのは、Javaに顕著な特徴かと思うのですが、
Matlabでもそれが可能です。
./libs/+Common/Utility.m
./libs/+Common/Figure.m
例えば上記のようにUtility, Figureのモジュールを
作成してフォルダを組むと、
Commonパッケージが作成されます。
このlibsディレクトリとそのサブディレクトリにパスを通せば
util = Common.Utility;
などとして呼び出せます。

クラスの作り方

クラスのファイルと、それを呼び出すファイルの
例を作ってみます。

Utility.m
classdef Utility
 properties(Constant)
  FontSizeVal = 16;
  FontSize = 'FontSize';
 end
 methods(Static)
  function DirName = setResultDir(NewDir)
   % @desc: method to create a new directory where result files are saved.
   % @input: NewDir: NewDirectory Name, for example '2014-11-02-NewDir'
   DirName = ['./results/' NewDir];
   mkdir(DirName);
  end
 end
end

こういうモジュールファイルを作ってみて、
呼び出して使ってみます。

util = Utility;
DirName = util.setResultDir('2014-11-02-New-Directory');

これが、初歩的な(というか原始的な?)クラスの使い方。
関連する複数の関数を1つのファイルに書いておくことが出来ます。
この形態は、モジュールて言うと思います。

インスタンス化

インスタンス化する(モジュールではない)
一般的な「クラス」については、
handleクラスを継承してあげる必要があります。

あんまり詳しいことは読んでいないんですが、
インスタンスとして値を保持し続けるには
handleクラスの継承が必要みたいです。
下記がサンプルコード。
引用元のを修正しています。

sensorlocest.m
classdef sensorlocest < handle 
    properties(GetAccess = public, SetAccess = private)
        x;
        y;
    end

    methods
        function sensors = sensorlocest(x,y)
            if nargin ~= 0
               sensors.x = x*rand;
               sensors.y = y*rand;
            end
        end
        function init(sensors,x,y)
            sensors.x = x*rand;
            sensors.y = y*rand;
        end
        function set.x(sensors,newx)
            sensors.x = newx;
        end
        function set.y(sensors,newy)
            sensors.y = newy;
        end
    end
end

下記で確認。

rehash;
lo = sensorlocest(1,2);

lo.init(10, 20);
lo.x
  => {random number}
lo.x = 1;
lo.x
  => 1

さり気なくsetter/getterを突っ込んでいますが、
今回は割愛します。

オブジェクト配列の作り方

Case1: 自身を配列にする場合

コンストラクタで自身を配列にするクラスを
作りたい場合はこちらをご参照ください。

child.m
classdef child < handle
 properties(SetAccess=private,GetAccess=public)
  age;
 end
 methods
  function c = child(age)
   if nargin ~=0
    c(5, 1) = child;
    for I=1:length(c),
     c(I).age = age;
    end
   end
  end
 end
end

動作確認:

children = child(20);
children(1).age
=> 20
children(2).age
=> 20

ここでのポイントは、
childクラスのコンストラクタにて

if nargin ~=0
end

をセットしているところです。これにより、
引数無しでもそのクラスを呼び出すことができるようになります。

具体的には、

c(5,1) = child;

が実行可能となっています。ここ、if nargin ~=0, ** end
がない場合には、引数が足りなくて実行できないといった
エラーにつながります。

Matlabではchildとchild()(引数なし)が
同じ意味を持つので、これは重要です。

Case2: 別のオブジェクトをプロパティとして持つ場合

デザインパタンを使っていく際にはコチラが
必要となってくると思います。

子クラスを親クラスの中のプロパティに
配列として呼び出すケース。
さっき作ったchildクラスも書き換えて使います。

child.m
classdef child < handle
 properties(GetAccess=public, SetAccess=public)
  name;
  age;
 end
 methods
  function c = child
   if nargin ~=0
    % write process which runs when the input exists
   end
  end
  function set.age(c, age)
   c.age = age;
  end
  function set.name(c, name)
   c.name = name;
  end
 end
end
parent.m
classdef parent < handle
 properties
  % give a data type
  children = child;
 end
 methods
  function p = parent(NumberChildren)
   % set object-ed array to children property
   p.children(NumberChildren, 1) = child;
  end
 end
end

この例では、parentクラス内のpはparentオブジェクトとなり、
そのプロパティであるchildrenが動的に作成される
childのオブジェクト配列になっています。

p = parent(3);
length(p.children)
=> 3
p.children(1).name = 'James';
p.children(1).name
=> James

申し訳程度に抽象クラスの作り方

これも本丸で、今回実はBuilderパタンていうのを
実装してまして、抽象クラスについても調べました。

Builder.m
classdef(Abstract) Builder < handle
 methods
  % never write the initializer in Abstract class

  % write only output and input.
  % "function", "end" and so on are not permitted.
  construct
 end
end

継承するときは、他の言語と同様に次のように書いてください。
抽象クラスで書いてあるメソッドを実装しないと、
エラーが発生します。

また、継承先をインスタンス化する場合には、
継承元の抽象クラスにてhandleクラスを
継承しておく必要があります。
抽象クラスに< handleと書くだけです。

ConcreteBuilder.m
classdef ConcreteBuilder < Builder
 methods
  function conctruct()
   % implement this method here!
  end
 end
end

こんな感じすかね。
必要に応じて記事アップデートします。

参考

setterとgetterについての記事

24
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
23