MATLAB Language
オブジェクト指向プログラミング
サーチ…
クラスの定義
クラスは、クラスと同じ名前の.m
ファイル内のclassdef
を使用して定義することができます。このファイルには、クラスメソッド内で使用するclassdef
... end
ブロックとローカル関数を含めることができます。
最も一般的なMATLABクラス定義の構造は次のとおりです。
classdef (ClassAttribute = expression, ...) ClassName < ParentClass1 & ParentClass2 & ...
properties (PropertyAttributes)
PropertyName
end
methods (MethodAttributes)
function obj = methodName(obj,arg2,...)
...
end
end
events (EventAttributes)
EventName
end
enumeration
EnumName
end
end
MATLABドキュメンテーション: クラス属性 、 プロパティ属性 、 メソッド属性 、 イベント属性 、 列挙クラスの制限 。
例のクラス:
Car
というクラスはCar.m
ファイルでCar.m
ように定義できます。
classdef Car < handle % handle class so properties persist
properties
make
model
mileage = 0;
end
methods
function obj = Car(make, model)
obj.make = make;
obj.model = model;
end
function drive(obj, milesDriven)
obj.mileage = obj.mileage + milesDriven;
end
end
end
コンストラクタは、クラスと同じ名前のメソッドであることに注意してください。 <コンストラクタは、その型のオブジェクトを初期化するオブジェクト指向プログラミングのクラスまたは構造の特別なメソッドです。コンストラクタは、通常、クラスと同じ名前を持つインスタンスメソッドであり、オブジェクトのメンバーの値をデフォルトまたはユーザ定義の値に設定するために使用できます。
このクラスのインスタンスは、コンストラクタを呼び出して作成できます。
>> myCar = Car('Ford', 'Mustang'); //creating an instance of car class
drive
メソッドを呼び出すと、走行距離が増えます
>> myCar.mileage
ans =
0
>> myCar.drive(450);
>> myCar.mileage
ans =
450
値とハンドルクラス
MATLABのクラスは、値クラスとハンドルクラスという2つの主要なカテゴリに分類されます。主な相違点は、値クラスのインスタンスをコピーすると、元のデータが新しいインスタンスにコピーされ、ハンドルクラスの場合は新しいインスタンスが元のデータを指し、新しいインスタンスの値を変更すると元のデータに変更されます。クラスはhandle
クラスから継承してhandle
として定義することができます。
classdef valueClass
properties
data
end
end
そして
classdef handleClass < handle
properties
data
end
end
次に
>> v1 = valueClass;
>> v1.data = 5;
>> v2 = v1;
>> v2.data = 7;
>> v1.data
ans =
5
>> h1 = handleClass;
>> h1.data = 5;
>> h2 = h1;
>> h2.data = 7;
>> h1.data
ans =
7
クラスと抽象クラスから継承
免責事項:ここに示した例は、抽象クラスと継承の使用を示すためのものであり、必ずしも実用的ではありません。また、MATLABではポリモーフィックなものがないので、抽象クラスの使用は制限されています。この例は、誰がクラスを作成し、別のクラスから継承し、共通クラスを定義するために抽象クラスを適用するかを示します。
抽象クラスの使用は、MATLABではかなり制限されていますが、それでも数回で有用になることがあります。
メッセージロガーが必要だとしましょう。以下のようなクラスを作成するかもしれません:
classdef ScreenLogger
properties(Access=protected)
scrh;
end
methods
function obj = ScreenLogger(screenhandler)
obj.scrh = screenhandler;
end
function LogMessage(obj, varargin)
if ~isempty(varargin)
varargin{1} = num2str(varargin{1});
fprintf(obj.scrh, '%s\n', sprintf(varargin{:}));
end
end
end
end
プロパティとメソッド
要するに、プロパティはオブジェクトの状態を保持し、メソッドはインタフェースのようなものであり、オブジェクトに対するアクションを定義します。
プロパティscrh
は保護されています。このため、コンストラクタで初期化する必要があります。このプロパティにアクセスする他のメソッド(getter)がありますが、この例の対処法はありません。プロパティとメソッドは、ドット記法とそれに続くメソッドまたはプロパティの名前を使用して、オブジェクトへの参照を保持する変数を介してアクセスできます。
mylogger = ScreenLogger(1); % OK
mylogger.LogMessage('My %s %d message', 'very', 1); % OK
mylogger.scrh = 2; % ERROR!!! Access denied
プロパティとメソッドはpublic、private、protectedのいずれかです。この場合、protectedは、継承されたクラスからscrh
にアクセスできますが、 scrh
からはアクセスできないことを意味します。デフォルトでは、すべてのプロパティとメソッドは公開されています。したがって、 LogMessage()
はクラス定義の外部で自由に使用できます。また、 LogMessage
は、オブジェクトがカスタムメッセージをログに記録するときに呼び出さなければならないことを意味するインタフェースを定義します。
応用
私が私のロガーを利用するスクリプトがあるとしましょう:
clc;
% ... a code
logger = ScreenLogger(1);
% ... a code
logger.LogMessage('something');
% ... a code
logger.LogMessage('something');
% ... a code
logger.LogMessage('something');
% ... a code
logger.LogMessage('something');
同じロガーを使用する複数の場所があり、ファイルにメッセージを書き込むなど、より洗練されたものに変更したい場合は、別のオブジェクトを作成する必要があります。
classdef DeepLogger
properties(SetAccess=protected)
FileName
end
methods
function obj = DeepLogger(filename)
obj.FileName = filename;
end
function LogMessage(obj, varargin)
if ~isempty(varargin)
varargin{1} = num2str(varargin{1});
fid = fopen(obj.fullfname, 'a+t');
fprintf(fid, '%s\n', sprintf(varargin{:}));
fclose(fid);
end
end
end
end
1行のコードを次のように変更してください:
clc;
% ... a code
logger = DeepLogger('mymessages.log');
上記の方法は単にファイルを開き、ファイルの最後にメッセージを追加して閉じます。現時点では、私のインターフェースと一貫性を持たせるために、メソッドの名前はLogMessage()
であることを忘れないでください。 MATLABは抽象クラスを使用することにより、developperを同じ名前に固執させることができます。任意のロガーの共通インターフェースを定義するとしましょう:
classdef MessageLogger
methods(Abstract=true)
LogMessage(obj, varargin);
end
end
このクラスからScreenLogger
とDeepLogger
両方を継承すると、 LogMessage()
が定義されていないと、MATLABはエラーを生成します。抽象クラスは、同じインタフェースを使用できる類似のクラスを構築するのに役立ちます。
この例のために、私は若干異なる変更を行います。 DeepLoggerは画面上とファイル内に同時にログメッセージを記録すると仮定します。のでScreenLogger
すでに画面上にログメッセージを、私は継承するつもりですDeepLogger
からScreenLoggger
繰り返しを避けるために。 ScreenLogger
は最初の行から離れても全く変更されません:
classdef ScreenLogger < MessageLogger
// the rest of previous code
ただし、 DeepLogger
ではLogMessage
メソッドの変更がさらに必要になります。
classdef DeepLogger < MessageLogger & ScreenLogger
properties(SetAccess=protected)
FileName
Path
end
methods
function obj = DeepLogger(screenhandler, filename)
[path,filen,ext] = fileparts(filename);
obj.FileName = [filen ext];
pbj.Path = pathn;
obj = obj@ScreenLogger(screenhandler);
end
function LogMessage(obj, varargin)
if ~isempty(varargin)
varargin{1} = num2str(varargin{1});
LogMessage@ScreenLogger(obj, varargin{:});
fid = fopen(obj.fullfname, 'a+t');
fprintf(fid, '%s\n', sprintf(varargin{:}));
fclose(fid);
end
end
end
end
まず、コンストラクタのプロパティを初期化するだけです。第2に、このクラスはScreenLogger
から継承するので、私はこのパラレルオブジェクトも初期化する必要があります。 ScreenLogger
コンストラクターは独自のオブジェクトを初期化するために1つのパラメーターを必要とするため、この行はさらに重要です。この行:
obj = obj@ScreenLogger(screenhandler);
単に「ScreenLoggerのコンストラクターに電話をかけ、スクリーンハンドラーで初期化する」と言っています。私がscrh
を保護されたものと定義したことはここでは注目に値する。したがって、 DeepLogger
からこのプロパティにも同様にアクセスできます。プロパティがプライベートとして定義されている場合それを初期化する唯一の方法は、コンスータを使用することです。
別の変更はセクションmethods
ます。繰り返しを避けるため、親クラスのLogMessage()
を呼び出してメッセージを画面に記録します。画面のロギングを改善するために何かを変更しなければならなかったら、今は1か所でやる必要があります。残りのコードはDeepLogger
一部とDeepLogger
です。
このクラスも抽象クラスMessageLogger
から継承するので、 DeepLogger
内のLogMessage()
も定義されていることを確認しなければなりませんDeepLogger
。 MessageLogger
から継承するのはちょっと難しいです。私は、 LogMessage
再定義が必須であると思う - 私の推測。
ロガーが適用されるコードに関しては、クラス内の共通インターフェースのおかげで、コード全体でこの1行を変更することは問題にならないでしょう。同じメッセージが以前と同じようにログオンされますが、さらにコードはそのようなメッセージをファイルに書き込みます。
clc;
% ... a code
logger = DeepLogger(1, 'mylogfile.log');
% ... a code
logger.LogMessage('something');
% ... a code
logger.LogMessage('something');
% ... a code
logger.LogMessage('something');
% ... a code
logger.LogMessage('something');
私は、これらの例がクラスの使用、継承の使用、抽象クラスの使用について説明してくれることを願っています。
PS。上記の問題に対する解決法は、多くのうちの1つです。あまり複雑ではない別の解決策は、 ScreenLoger
をFileLogger
などのような別のロガーのコンポーネントにすることですScreenLogger
はプロパティの1つに保持されます。 LogMessage
は単にScreenLogger
LogMessage
を呼び出し、スクリーン上にテキストを表示します。 MATLABでクラスがどのように動作するかをむしろ示すために、より複雑なアプローチを選択しました。以下のサンプルコード:
classdef DeepLogger < MessageLogger
properties(SetAccess=protected)
FileName
Path
ScrLogger
end
methods
function obj = DeepLogger(screenhandler, filename)
[path,filen,ext] = fileparts(filename);
obj.FileName = [filen ext];
obj.Path = pathn;
obj.ScrLogger = ScreenLogger(screenhandler);
end
function LogMessage(obj, varargin)
if ~isempty(varargin)
varargin{1} = num2str(varargin{1});
obj.LogMessage(obj.ScrLogger, varargin{:}); % <-------- thechange here
fid = fopen(obj.fullfname, 'a+t');
fprintf(fid, '%s\n', sprintf(varargin{:}));
fclose(fid);
end
end
end
end
コンストラクタ
コンストラクタは、オブジェクトのインスタンスが作成されるときに呼び出されるクラス内の特別なメソッドです。これは入力パラメータを受け入れる通常のMATLAB関数ですが、特定の規則にも従わなければなりません。
MATLABがデフォルトのものを作成するので、コンストラクタは必須ではありません。しかし、実際には、これはオブジェクトの状態を定義する場所です。たとえば、 属性を指定することでプロパティを制限することができます 。次に、コンストラクタは、実際にはコンストラクタの入力パラメータによって送信できるデフォルトまたはユーザ定義の値によって、そのようなプロパティを初期化できます。
単純なクラスのコンストラクタを呼び出す
これは単純なクラスPerson
です。
classdef Person
properties
name
surname
address
end
methods
function obj = Person(name,surname,address)
obj.name = name;
obj.surname = surname;
obj.address = address;
end
end
end
コンストラクタの名前は、クラスの名前と同じです。したがって、コンストラクタはそのクラスの名前で呼び出されます。 Person
クラスは、次のように作成できます。
>> p = Person('John','Smith','London')
p =
Person with properties:
name: 'John'
surname: 'Smith'
address: 'London'
子クラスのコンストラクタを呼び出す
共通のプロパティまたはメソッドを共有する場合、クラスは親クラスから継承できます。クラスが別のクラスから継承される場合、親クラスのコンストラクタを呼び出さなければならない可能性があります。
クラスMember
クラスから継承するPerson
ので、 Member
クラスPersonと同じプロパティを使用していますが、それはまた、追加payment
その定義に。
classdef Member < Person
properties
payment
end
methods
function obj = Member(name,surname,address,payment)
obj = obj@Person(name,surname,address);
obj.payment = payment;
end
end
end
Person
クラスと同様に、 Member
はそのコンストラクタを呼び出して作成されます:
>> m = Member('Adam','Woodcock','Manchester',20)
m =
Member with properties:
payment: 20
name: 'Adam'
surname: 'Woodcock'
address: 'Manchester'
Person
のコンストラクタには3つの入力パラメータが必要です。 Member
はこの事実を尊重しなければならないため、3つのパラメータを持つPerson
クラスのコンストラクタを呼び出します。それは次の行によって実現されます:
obj = obj@Person(name,surname,address);
上記の例は、子クラスが親クラスの情報を必要とする場合を示しています。これは、 Member
コンストラクターが4つのパラメーターを必要とする理由です.3つはその親クラス用であり、もう1つはそれ自身のパラメーターです。