Main Content

开发协同工作的类

构建类

此示例讨论如何设计和实现两个通过事件和侦听程序进行交互的类。这两个类分别表示银行帐户和帐户管理器。

要设计表示银行帐户的类,首先要确定构成银行帐户的数据元素和操作。例如,银行帐户包含:

  • 帐号

  • 帐户余额

  • 状态(open、closed 等)

您必须对银行帐户执行一些操作:

  • 为每个银行帐户创建一个对象

  • 存款

  • 取款

  • 生成语句

  • 保存并加载 BankAccount 对象

如果余额太低,在您尝试取款时,银行帐户会发出通知。当此事件发生时,银行帐户会向其他用于侦听通知的实体广播通知。在本示例中,用一个简化版的帐户管理程序来执行此任务。

在本示例中,帐户管理程序确定所有银行帐户的状态。该程序监控帐户余额并为下列三个值之一赋值:

  • open - 帐户余额为正值

  • overdrawn - 帐户余额透支,但透支额不超过 200 美元。

  • closed - 帐户余额透支超过 200 美元。

这些功能定义 BankAccountAccountManager 类的要求。只包括满足您特定目标所需的功能。通过子类化 BankAccount 并向子类添加更多特定功能,以支持特殊类型的帐户。根据需要扩展 AccountManager,以支持新帐户类型。

指定类组件

类将数据存储在属性中,用方法实现操作,并支持用事件和侦听程序进行通知。以下部分说明 BankAccountAccountManager 类如何定义这些组件。

类数据

类会定义以下属性来存储帐号、帐户余额和帐户状态:

  • AccountNumber - 该属性存储标识帐户的编号。创建类的实例时,MATLAB® 会为此属性赋值。只有 BankAccount 类方法可以设置此属性。SetAccess 属性是 private

  • AccountBalance - 该属性存储帐户的当前余额。存款和取款等类操作会为该属性进行相应赋值。只有 BankAccount 类方法可以设置此属性。SetAccess 属性是 private

  • AccountStatus - BankAccount 类定义该属性的默认值。每当 AccountBalance 的值低于 0 时,AccountManager 类方法便会更改该值。Access 特性指定只有 AccountManagerBankAccount 类可以访问该属性。

  • AccountListener - 用于存储 InsufficientFunds 事件侦听程序。保存 BankAccount 对象不会保存此属性,因为加载对象时必须重新创建侦听程序。

类操作

以下方法实现类构建中定义的操作:

  • BankAccount - 接受帐号和初始余额,以创建表示帐户的对象。

  • deposit - 发生存款交易时,更新 AccountBalance 属性。

  • withdraw - 发生取款交易时,更新 AccountBalance 属性。

  • getStatement - 显示帐户信息。

  • loadobj - 从 MAT 文件加载对象时,重新创建帐户管理侦听程序。

类事件

帐户管理程序会更改具有负余额的银行帐户的状态。要实现此操作,BankAccount 类会在取款导致负余额时触发一个事件。因此,触发 InsufficientFunds 事件的行为在 withdraw 方法中发生。

要定义事件,请在 events 代码块中指定名称。通过调用 notify 句柄类方法触发事件。由于 InsufficientFunds 不是预定义的事件,因此您可以用任何 char 向量命名它,并通过任何操作触发它。

BankAccount 类实现

请务必确保只有一组数据与 BankAccount 类的任一对象相关联。例如,您不希望对象的独立副本具有不同的帐户余额值。因此,请将 BankAccount 类当作句柄类来实现。给定句柄对象的所有副本都引用相同的数据。

BankAccount 类概要

BankAccount讨论
classdef BankAccount < handle

句柄类,因为任何 BankAccount 实例都应该只有一个副本。句柄类和值类的比较

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

AccountStatus 包含由当前余额确定的帐户状态。访问仅限于 BankAccountAccountManager 类。类成员访问

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

AccountManager 类方法访问的 AccountStatus 属性。

AccountNumberAccountBalance 属性拥有私有 set 访问权限。

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

deposit 调整 AccountBalance 属性的值。

如果 AccountStatusclosed,但后续存款使 AccountBalance 变为正值,则 AccountStatus 将重置为 open

      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 属性。如果取款导致帐户余额为负值,notify 将触发 InsufficientFunds 事件。

有关侦听程序的详细信息,请参阅事件和侦听程序语法

      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 (Static)

静态方法代码块的开始。请参阅静态方法

      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

静态方法代码块的结束

classdef 的结束

 展开类代码

构建 AccountManager

AccountManager 类旨在为帐户提供服务。对于 BankAccount 类,AccountManager 类会侦听导致余额下降到负值范围的取款。当 BankAccount 对象触发 InsufficientFunds 事件时,AccountManager 会重置帐户状态。

AccountManager 类不存储数据,因此不需要属性。BankAccount 对象存储侦听程序对象的句柄。

AccountManager 执行以下两项操作:

  • 根据取款结果,为每个帐户赋一个状态

  • 通过监控帐户余额向系统添加帐户。

类组件

AccountManager 类实现以下两个方法:

  • assignStatus - 将状态赋给 BankAccount 对象的方法。用作侦听程序回调。

  • addAccount - 创建 InsufficientFunds 侦听程序的方法。

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

addAccountBankAccount 类定义的 InsufficentFunds 事件创建侦听程序。

请参阅Control Listener Lifecycle

   end
end

methodsclassdefend 语句。

 展开类代码

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