如何设计合理的面向对象结构:库存系统事务类设计疑问
我刚注册了大学的第一门面向对象(OO)课程,目前有些迷茫。我需要用UML设计一个库存管理系统,但在某些方法的归属上遇到了瓶颈。
我已定义Transaction类,按我的理解,类应封装操作特定数据集的所有方法和属性。因此,如果InventoryManager类需要获取所有交易记录,我认为Transaction类应包含类似GetAllTransactions的方法并返回List<Transaction>。但Transaction类如何返回自身实例的列表呢?以下是我设计的TransactionManager和Transaction类的UML文本表示及代码构想(方法命名仅为传达问题意图)。
能否有人从概念层面展示正确的设计方式?
现有UML类设计
TransactionManager类
| TransactionManager |
|---|
| private List transactions |
| public List GetAllTransactionsFromTransactionClass(); |
Transaction类
| Transaction |
|---|
| private string transactionId |
| Date date |
| private double price |
| public void Transaction() {} |
| public List GetAllTransactions(); |
另外,若我在GetAllTransactions方法中创建一个交易记录列表的局部变量(用于返回),每次创建新Transaction实例时会不会引发循环引用之类的问题?
我的代码构想如下:
public TransactionManager { public GetAllTransactionsFromTransactionClass { List<Transaction> transactions = Transaction.GetAllTransactions(); } } public Transaction { public Transaction() public List<Transaction> GetAllTransactions() { List<Transaction> transactions = new List<Transaction>(); transactions.Add(new Transaction()); return transactions; } }
正确的设计思路(概念层面)
1. 职责分离:区分实体类与管理器类
Transaction是实体类,它只应该封装单个交易的属性和行为(比如计算交易金额、验证交易ID格式等),不负责管理所有交易的集合。
TransactionManager(或InventoryManager)是管理器类,它的职责才是维护交易列表、提供查询/新增/删除交易的方法。把GetAllTransactions放在管理器类里才符合单一职责原则。
2. 修正后的UML设计
TransactionManager类
| TransactionManager |
|---|
| private List |
| + void AddTransaction(Transaction transaction) |
| + List |
| + Transaction GetTransactionById(string id) |
Transaction类
| Transaction |
|---|
| - string _transactionId |
| - Date _date |
| - double _price |
| + Transaction(string transactionId, Date date, double price) |
| + string TransactionId { get; } |
| + Date Date { get; } |
| + double Price { get; } |
| + bool IsValid() // 示例:验证当前交易的合法性 |
3. 修正后的代码示例
public class TransactionManager { // 维护交易集合的私有字段 private List<Transaction> _transactions = new List<Transaction>(); // 添加交易的方法 public void AddTransaction(Transaction transaction) { if(transaction.IsValid()) { _transactions.Add(transaction); } } // 获取所有交易的方法 public List<Transaction> GetAllTransactions() { // 返回副本避免外部直接修改内部集合 return new List<Transaction>(_transactions); } } public class Transaction { // 私有字段封装属性 private readonly string _transactionId; private readonly DateTime _date; private readonly double _price; // 构造函数初始化属性 public Transaction(string transactionId, DateTime date, double price) { _transactionId = transactionId; _date = date; _price = price; } // 只读属性暴露数据 public string TransactionId => _transactionId; public DateTime Date => _date; public double Price => _price; // 实体自身的行为:验证当前交易是否合法 public bool IsValid() { return !string.IsNullOrEmpty(_transactionId) && _price >= 0; } }
4. 关于循环引用的疑问
你当前的代码里,Transaction.GetAllTransactions()每次创建新的Transaction实例并加入列表,这不会直接导致循环引用,但会出现逻辑错误:每次调用这个方法都会生成一个只包含新交易的列表,而不是实际存储的所有交易。
正确的设计中,交易集合由管理器维护,实体类不需要自己生成实例列表,自然不会有这类问题。
内容的提问来源于stack exchange,提问作者Scott

