Main Content

連携するクラスの開発

クラスの作成

この例では、イベントおよびリスナーを通じて連携する 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 です。

  • AccountStatusBankAccount クラスがこのプロパティの既定値を定義します。AccountManager クラス メソッドは、AccountBalance の値が 0 より低くなったときにこの値を変更します。Access 属性により、AccountManager クラスおよび BankAccount クラスだけがこのプロパティにアクセスできるよう指定されます。

  • AccountListenerInsufficientFunds イベント リスナーのストレージ。オブジェクトを読み込むときにリスナーの再作成が必要なため、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

BankAccount のインスタンスはどれもコピーが 1 つのみとする必要があるため、ハンドル クラスとします。ハンドル クラスと値クラスの比較

   properties (Access = ?AccountManager)
        AccountStatus = 'open'
   end

AccountStatus には、現在の預金残高によって判定された口座の状態が含まれます。アクセスは BankAccount クラスと AccountManager クラスに制限されます。クラス メンバーのアクセス

   properties (SetAccess = private)
      AccountNumber
      AccountBalance
   end
   properties (Transient)
      AccountListener
   end

AccountStatus プロパティには AccountManager クラス メソッドによってアクセスします。

AccountNumber および AccountBalance プロパティにはプライベートの SetAccess が指定されています。

AccountListener property は過渡的なものなので、リスナー ハンドルは保存されません。

プロパティの属性を参照してください。

   events
      InsufficientFunds
   end

クラスでは InsufficientFunds というイベントが定義されます。withdraw メソッドは預金残高が負になったときにイベントをトリガーします。

イベントとリスナーの詳細については、イベントを参照してください。

   methods

通常のメソッドのブロックです。構文については、メソッドの構文を参照してください。

      function BA = BankAccount(AccountNumber,InitialBalance)
         BA.AccountNumber = AccountNumber;
         BA.AccountBalance = InitialBalance;
         BA.AccountListener = AccountManager.addAccount(BA);
      end

コンストラクターは、入力引数によってプロパティ値を初期化します。

AccountManager.addAccountAccountManager クラスの静的メソッドです。InsufficientFunds イベントのリスナーを作成し、リスナー ハンドルを AccountListener プロパティに保存します。

      function deposit(BA,amt)
         BA.AccountBalance = BA.AccountBalance + amt;
         if BA.AccountBalance > 0
            BA.AccountStatus = 'open';
         end
      end

depositAccountBalance プロパティの値を調整します。

AccountStatusclosed で、その後の入金によって AccountBalance が正の範囲になった場合、AccountStatusopen にリセットされます。

      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

AccountBalance プロパティを更新します。引き出しにより預金残高が負値になる場合は、notifyInsufficientFunds イベントをトリガーします。

リスナーの詳細については、イベントとリスナーの構文を参照してください。

      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

loadobj メソッド:

  • 読み込み操作が失敗した場合に、struct からオブジェクトを作成します。

  • 新しく作成された BankAccount オブジェクトを基にしてリスナーを再作成します。

オブジェクトの保存と読み込みの詳細については、オブジェクトの保存と読み込みのプロセスを参照してください。

   end
end

静的 methods ブロックの終端

classdef の終端

 クラス コードの拡張

AccountManager クラスの作成

AccountManager クラスの目的は口座に対するサービスを提供することです。BankAccount クラスに対して、AccountManager クラスは預金残高を負の範囲に下げる引き出しをリッスンします。BankAccount オブジェクトが InsufficientFunds イベントをトリガーすると、AccountManager は口座の状態をリセットします。

AccountManager クラスはデータを保存しないので、プロパティは必要ありません。BankAccount オブジェクトはリスナー オブジェクトのハンドルを保存します。

AccountManager は 2 つの操作を実行します。

  • 引き出し結果に基づき各口座に状態を割り当てる

  • 預金残高を監視して口座をシステムに追加する

クラスのコンポーネント

AccountManager クラスは 2 つのメソッドを実装します。

  • assignStatusBankAccount オブジェクトに状態を割り当てるメソッド。リスナー コールバックとして機能します。

  • addAccountInsufficientFunds リスナーを作成するメソッド。

AccountManager クラスの実装

AccountManager オブジェクトは不要であるため、AccountManager クラスは両メソッドを静的メソッドとして実装します。これらのメソッドは BankAccount オブジェクトに対し操作を行います。

AccountManager のインスタンス化は意図されていません。AccountManager クラスの機能を BankAccount クラスから分けることにより、柔軟性と拡張性が高まります。たとえば、これにより以下が可能になります。

  • AccountManager クラスを拡張して他のタイプの口座をサポートできるようにし、その一方で各口座のクラスをシンプルで特化したものに保つ。

  • 保存され読み込まれた BankAccount オブジェクトの互換性に影響を与えずに、口座の状態に関する条件を変更する。

  • 各サブクラスに対し口座管理機能を実装することを求めずに、すべての口座の共通事項を括り出す Account スーパークラスを開発する。

AccountManager クラスの概要

AccountManager クラス説明
classdef AccountManager

このクラスは InsufficentFunds イベント リスナーとリスナー コールバックを定義します。

   methods (Static)

定義されるメソッドは静的なメソッドであるため、このクラスのインスタンスを作成する必要はありません。静的メソッドを参照してください。

   function assignStatus(BA)
      if BA.AccountBalance < 0
         if BA.AccountBalance < -200
            BA.AccountStatus = 'closed';
         else
            BA.AccountStatus = 'overdrawn';
         end
      end
   end

assignStatus メソッドは InsufficentFunds イベント リスナーのコールバックです。これは、AccountBalance プロパティの値に基づいて BankAccount オブジェクトの AccountStatus プロパティの値を決定します。

BankAccount クラスのコンストラクターは、このリスナーを作成して保存するために AccountManageraddAccount メソッドを呼び出します。

   function lh = addAccount(BA)
      lh = addlistener(BA, 'InsufficientFunds', ...
         @(src, ~)AccountManager.assignStatus(src));
   end

addAccount は、BankAccount クラスによって定義されている InsufficentFunds イベントに対しリスナーを作成します。

リスナー ライフサイクルの制御を参照してください。

   end
end

methods および classdefend ステートメント。

 クラス コードの拡張

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
-------------------------