#なぜ書くか
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;
などとして呼び出せます。
クラスの作り方
クラスのファイルと、それを呼び出すファイルの
例を作ってみます。
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クラスの継承が必要みたいです。
下記がサンプルコード。
引用元のを修正しています。
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: 自身を配列にする場合
コンストラクタで自身を配列にするクラスを
作りたい場合はこちらをご参照ください。
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クラスも書き換えて使います。
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
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パタンていうのを
実装してまして、抽象クラスについても調べました。
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**と書くだけです。
classdef ConcreteBuilder < Builder
methods
function conctruct()
% implement this method here!
end
end
end
こんな感じすかね。
必要に応じて記事アップデートします。