連携するクラスの開発
クラスの作成
この例では、イベントおよびリスナーを通じて連携する 2 つのクラスの設計と実装の手法について説明します。2 つのクラスは銀行口座とアカウント マネージャーを表します。
銀行口座を表すクラスを設計するには、まずデータの要素と、銀行口座を抽象化する操作を決めます。たとえば、銀行口座には以下の要素があります。
口座番号
預金残高
状態 (open、closed など)
銀行口座では、次のような操作を行わなければなりません。
各銀行口座のオブジェクトを作成する
預金する
預金を引き出す
明細書を生成する
BankAccount
オブジェクトの保存と読み込みを行う
残高が足りないときに預金を引き出そうとすると、銀行口座から通知がブロードキャストされます。このイベントが発生すると、銀行口座は、これらの通知をリッスンするように設計された他のエンティティに通知をブロードキャストします。この例では、アカウント マネージャー プログラムの簡易版がこのタスクを実行します。
この例では、アカウント マネージャー プログラムがすべての銀行口座の状態を判定します。このプログラムは預金残高を監視し、次の 3 つの値のいずれかを代入します。
open
— 預金残高は正の値ですoverdrawn
— 預金の引き出しが残高を超えていますが、$200 以下の超過です。closed
— 預金の引き出しが残高よりも $200 超過しています。
これらの機能により BankAccount
および AccountManager
クラスの要件が定義されます。具体的な目的の実現に必要な機能だけを含めてください。特殊なタイプの口座をサポートするには、BankAccount
をサブクラスに分け、より具体的な機能をサブクラスに追加します。必要に応じて AccountManager
を拡張して、新たな口座タイプをサポートします。
クラスのコンポーネントの指定
クラスはデータをプロパティに保存し、操作をメソッドで実装し、通知にイベントとリスナーで対応します。以下では、BankAccount
および AccountManager
クラスでこうしたコンポーネントがどのように定義されるかを示します。
クラス データ
このクラスでは、口座番号、預金残高および口座の状態を保存する以下のプロパティを定義します。
AccountNumber
— 特定のアカウントを識別する番号を保存するプロパティ。クラスのインスタンスを作成するときに、MATLAB® はこのプロパティに値を代入します。BankAccount
クラス メソッドだけがこのプロパティを設定できます。SetAccess
属性はprivate
です。AccountBalance
— 現在の預金残高を保存するプロパティ。預金と引き出しというクラス操作によって、このプロパティに値が代入されます。BankAccount
クラス メソッドだけがこのプロパティを設定できます。SetAccess
属性はprivate
です。AccountStatus
—BankAccount
クラスがこのプロパティの既定値を定義します。AccountManager
クラス メソッドは、AccountBalance
の値が0
より低くなったときにこの値を変更します。Access
属性により、AccountManager
クラスおよびBankAccount
クラスだけがこのプロパティにアクセスできるよう指定されます。AccountListener
—InsufficientFunds
イベント リスナーのストレージ。オブジェクトを読み込むときにリスナーの再作成が必要なため、BankAccount
オブジェクトを保存してもこのプロパティは保存されません。
クラスの操作
以下のメソッドにより、クラスの形成で定義した操作を実装します。
BankAccount
— 口座番号と初期残高を受け取り、口座を表すオブジェクトを作成します。deposit
— 預金の取引があると、AccountBalance
プロパティを更新します。withdraw
— 引き出しがあると、AccountBalance
プロパティを更新します。getStatement
— 口座に関する情報を表示します。loadobj
— MAT ファイルからオブジェクトを読み込むときに、アカウント マネージャーのリスナーを再作成します。
クラス イベント
アカウント マネージャー プログラムは、残高が負値となっている銀行口座の状態を変更します。このアクションを実装するには、引き出しにより残高が負になる場合に、BankAccount
クラスがイベントをトリガーするようにします。したがって、InsufficientFunds
イベントのトリガーは、withdraw
メソッド内から発生します。
イベントを定義するには、events
ブロック内で名前を指定します。notify
ハンドル クラスのメソッドへの呼び出しによって、イベントをトリガーします。InsufficientFunds
はあらかじめ定義されたイベントではないため、任意の char
ベクトルを使用して名前を付けることや、任意のアクションによってトリガーすることができます。
BankAccount
クラスの実装
BankAccount
クラスのいずれのオブジェクトにも、データを必ず 1 セットのみ関連付けるようにすることが大切です。たとえば、値が異なる預金残高のオブジェクトの独立したコピーがあると問題です。そのため、BankAccount
クラスはハンドル クラスとして実装します。与えられたハンドル オブジェクトのコピーはすべて、同じデータを参照します。
BankAccount
クラスの概要
BankAccount クラス | 説明 |
---|---|
classdef BankAccount < handle
|
|
properties (Access = ?AccountManager) AccountStatus = 'open' end |
|
properties (SetAccess = private) AccountNumber AccountBalance end properties (Transient) AccountListener end |
プロパティの属性を参照してください。 |
events
InsufficientFunds
end
| クラスでは イベントとリスナーの詳細については、イベントを参照してください。 |
methods | 通常のメソッドのブロックです。構文については、メソッドの構文を参照してください。 |
function BA = BankAccount(AccountNumber,InitialBalance) BA.AccountNumber = AccountNumber; BA.AccountBalance = InitialBalance; BA.AccountListener = AccountManager.addAccount(BA); end | コンストラクターは、入力引数によってプロパティ値を初期化します。
|
function deposit(BA,amt) BA.AccountBalance = BA.AccountBalance + amt; if BA.AccountBalance > 0 BA.AccountStatus = 'open'; end end |
|
function withdraw(BA,amt) if (strcmp(BA.AccountStatus,'closed')&& ... BA.AccountBalance < 0) disp(['Account ',num2str(BA.AccountNumber),... ' has been closed.']) return end newbal = BA.AccountBalance - amt; BA.AccountBalance = newbal; if newbal < 0 notify(BA,'InsufficientFunds') end end |
リスナーの詳細については、イベントとリスナーの構文を参照してください。 |
function getStatement(BA) disp('-------------------------') disp(['Account: ',num2str(BA.AccountNumber)]) ab = sprintf('%0.2f',BA.AccountBalance); disp(['CurrentBalance: ',ab]) disp(['Account Status: ',BA.AccountStatus]) disp('-------------------------') end end | 口座に関する選択された情報を表示します。このセクションは通常 methods ブロックでも終端します。 |
methods (Static) | 静的 methods ブロックの冒頭。静的メソッドを参照してください。 |
function obj = loadobj(s) if isstruct(s) accNum = s.AccountNumber; initBal = s.AccountBalance; obj = BankAccount(accNum,initBal); else obj.AccountListener = AccountManager.addAccount(s); end end |
オブジェクトの保存と読み込みの詳細については、オブジェクトの保存と読み込みのプロセスを参照してください。 |
end end | 静的 methods ブロックの終端
|
AccountManager
クラスの作成
AccountManager
クラスの目的は口座に対するサービスを提供することです。BankAccount
クラスに対して、AccountManager
クラスは預金残高を負の範囲に下げる引き出しをリッスンします。BankAccount
オブジェクトが InsufficientFunds
イベントをトリガーすると、AccountManager
は口座の状態をリセットします。
AccountManager
クラスはデータを保存しないので、プロパティは必要ありません。BankAccount
オブジェクトはリスナー オブジェクトのハンドルを保存します。
AccountManager
は 2 つの操作を実行します。
引き出し結果に基づき各口座に状態を割り当てる
預金残高を監視して口座をシステムに追加する
クラスのコンポーネント
AccountManager
クラスは 2 つのメソッドを実装します。
assignStatus
—BankAccount
オブジェクトに状態を割り当てるメソッド。リスナー コールバックとして機能します。addAccount
—InsufficientFunds
リスナーを作成するメソッド。
AccountManager
クラスの実装
AccountManager
オブジェクトは不要であるため、AccountManager
クラスは両メソッドを静的メソッドとして実装します。これらのメソッドは BankAccount
オブジェクトに対し操作を行います。
AccountManager
のインスタンス化は意図されていません。AccountManager
クラスの機能を BankAccount
クラスから分けることにより、柔軟性と拡張性が高まります。たとえば、これにより以下が可能になります。
AccountManager
クラスを拡張して他のタイプの口座をサポートできるようにし、その一方で各口座のクラスをシンプルで特化したものに保つ。保存され読み込まれた
BankAccount
オブジェクトの互換性に影響を与えずに、口座の状態に関する条件を変更する。各サブクラスに対し口座管理機能を実装することを求めずに、すべての口座の共通事項を括り出す
Account
スーパークラスを開発する。
AccountManager
クラスの概要
AccountManager クラス | 説明 |
---|---|
classdef AccountManager
| このクラスは |
methods (Static) | 定義されるメソッドは静的なメソッドであるため、このクラスのインスタンスを作成する必要はありません。静的メソッドを参照してください。 |
function assignStatus(BA) if BA.AccountBalance < 0 if BA.AccountBalance < -200 BA.AccountStatus = 'closed'; else BA.AccountStatus = 'overdrawn'; end end end |
|
function lh = addAccount(BA) lh = addlistener(BA, 'InsufficientFunds', ... @(src, ~)AccountManager.assignStatus(src)); end |
リスナー ライフサイクルの制御を参照してください。 |
end end |
|
BankAccount
オブジェクトの使用
BankAccount
クラスは非常に簡単ですが、MATLAB クラスの動作仕様を説明します。たとえば、口座番号と初回預入金 $500 を使用して BankAccount
オブジェクトを作成します。
BA = BankAccount(1234567,500)
BA = BankAccount with properties: AccountNumber: 1234567 AccountBalance: 500 AccountListener: [1x1 event.listener]
getStatement
メソッドを使用して状態をチェックします。
getStatement(BA)
------------------------- Account: 1234567 CurrentBalance: 500.00 Account Status: open -------------------------
$600 の引き出しを行うと、預金残高が負値になります。
withdraw(BA,600) getStatement(BA)
------------------------- Account: 1234567 CurrentBalance: -100.00 Account Status: overdrawn -------------------------
$600 の引き出しにより InsufficientFunds
イベントがトリガーされました。現在 AccountManager
クラスによって定義されている条件に従い、状態が overdrawn
になります。
もう一度 $200 を引き出します。
withdraw(BA,200) getStatement(BA)
------------------------- Account: 1234567 CurrentBalance: -300.00 Account Status: closed -------------------------
AccountStatus
はリスナーにより closed
に設定されました。これ以上引き出そうとしても、イベントのトリガーなしでブロックされます。
withdraw(BA,100)
Account 1234567 has been closed.
預金によって AccountBalance
が正の値に戻ると、AccountStatus
は open に戻り、再び引き出すことが可能になります。
deposit(BA,700) getStatement(BA)
------------------------- Account: 1234567 CurrentBalance: 400.00 Account Status: open -------------------------