开发协同工作的类
构建类
此示例讨论如何设计和实现两个通过事件和侦听程序进行交互的类。这两个类分别表示银行帐户和帐户管理器。
要设计表示银行帐户的类,首先要确定构成银行帐户的数据元素和操作。例如,银行帐户包含:
帐号
帐户余额
状态(open、closed 等)
您必须对银行帐户执行一些操作:
为每个银行帐户创建一个对象
存款
取款
生成语句
保存并加载
BankAccount
对象
如果余额太低,在您尝试取款时,银行帐户会发出通知。当此事件发生时,银行帐户会向其他用于侦听通知的实体广播通知。在本示例中,用一个简化版的帐户管理程序来执行此任务。
在本示例中,帐户管理程序确定所有银行帐户的状态。该程序监控帐户余额并为下列三个值之一赋值:
open
- 帐户余额为正值overdrawn
- 帐户余额透支,但透支额不超过 200 美元。closed
- 帐户余额透支超过 200 美元。
这些功能定义 BankAccount
和 AccountManager
类的要求。只包括满足您特定目标所需的功能。通过子类化 BankAccount
并向子类添加更多特定功能,以支持特殊类型的帐户。根据需要扩展 AccountManager
,以支持新帐户类型。
指定类组件
类将数据存储在属性中,用方法实现操作,并支持用事件和侦听程序进行通知。以下部分说明 BankAccount
和 AccountManager
类如何定义这些组件。
类数据
类会定义以下属性来存储帐号、帐户余额和帐户状态:
AccountNumber
- 该属性存储标识帐户的编号。创建类的实例时,MATLAB® 会为此属性赋值。只有BankAccount
类方法可以设置此属性。SetAccess
属性是private
。AccountBalance
- 该属性存储帐户的当前余额。存款和取款等类操作会为该属性进行相应赋值。只有BankAccount
类方法可以设置此属性。SetAccess
属性是private
。AccountStatus
-BankAccount
类定义该属性的默认值。每当AccountBalance
的值低于0
时,AccountManager
类方法便会更改该值。Access
特性指定只有AccountManager
和BankAccount
类可以访问该属性。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
| 句柄类,因为任何 |
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 (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 |
有关保存和加载对象的详细信息,请参阅对象的保存和加载过程 |
end end | 静态方法代码块的结束
|
构建 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
| 此类定义 |
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 -------------------------