这是一个架构/最佳实践问题,而不是其他任何问题,所以请随意添加两美分。我知道我在标题中声明了状态,但这适用于对象的任何基本属性。我认为下面的帐户示例将有助于证明我的问题比状态好一点。
以下是一个示例帐户对象:
public class Account
{
private IList<Transaction> _transactions;
public AddTransaction(trans as Transaction)
{
_transaction.add(trans)
}
}
现在假设我想开始记录每次使用此对象添加事务时的历史记录。
public class AccountHistory
{
private DateTime _historyDate;
private String _details;
public AccountHistory(string details)
{
_historyDate = DateTime.Now;
_details = details;
}
}
在这个级别我通常会做的是将一组历史事件添加到帐户对象中,并添加一行代码以在AddTransaction()方法中创建一个历史事件,如下所示
public AddTransaction(trans as Transaction)
{
_transaction.add(trans);
**_historyEvents.add(new AccountHistory("Transaction Added: " + trans.ToString());**
}
现在下一部分是问题开始出现的地方。假设我想进行批量发布,并且我希望保留一份记录,说明在此批量发布中哪些帐户已更改为报表,或者我是否需要稍后撤消。所以我会创建一个像这样的对象。
public class HistoryGroup()
{
private IList<AccountHistory> _events;
}
从这里我看到一些不同的选项来处理这个问题,因为上面的示例代码无法处理它。
1)在Service类型对象中创建一个函数,该对象循环调用AddTransaction()方法的帐户列表,并创建与HistoryGroup相关的历史记录
public void AddTransactions(IList<Account> accounts, Transaction trans)
{
HistoryGroup history = new HistoryGroup();
for (int x=0;x <=accounts.Count - 1; x++)
{
accounts(x).AddTransaction(trans);
history.AddEvent(new AccountHistory("Added Transaction: " + trans.ToString();
}
}
2)将一些类型的HistoryManager对象与要添加的事务一起传递到AddTransaction方法中。然后该函数可以使用历史管理器来创建记录。
好的这篇文章足够长了。如果我不够清楚,请告诉我。谢谢你输入。
答案 0 :(得分:9)
你的方法可能运行得很好,但让我提出一个替代方案。
为什么不向Account类添加TransactionAdded事件。
然后,您可以从(我猜这里)订阅HistoryGroup对象,以便每次触发Event时都添加一个新的AccountHistory对象。
<强>更新强>
正如评论中所提到的,实现目标的另一种方法是让HistoryGroup实现一个接口(ITransactionLogger或类似的东西),然后修改Account,以便可以注入ITransactionLogger依赖项。
从复杂性和调试的角度来看,使用这些路径中的任何一个都会使事情变得更容易管理,但是不允许像事件这样的多个记录器。
这将使您的代码更灵活,同时允许对TransactionAdded事件感兴趣的其他消费者进行订阅。
答案 1 :(得分:2)
我在某些方面同意贾斯汀的回答,但OP上的一个标签是POCO;将事件添加到Account类将在某些方面取消POCO。
如果您正在使用AOP等,您可以使用拦截(大多数IoC框架,包括Unity和Castle提供此功能)来获取感兴趣的事务。
拦截的好处是您的Account类与AccountHistory类没有任何耦合,拦截可以根据您想要的任何规则进行高度配置,并且可以在不强制重新编译应用程序的情况下轻松更改(如果您将AccountHistory放入与拦截处理程序不同的程序集)。通过使用拦截,您可以使您的代码更专注于业务领域,而不是可以被视为基础架构任务(审计)。
同样,这是您工具箱的另一种选择;如果您因任何原因不需要通过电线序列化您的POCO,那么通过Justin建议的事件实施观察者模式(GoF)可能是一种更轻量级的方法。
答案 2 :(得分:1)
四人帮似乎都这么认为。交易,历史跟踪和不执行都是command pattern合同的一部分。您可以使用堆栈实现历史记录。以下是包含合同的相关代码片段,请注意并非所有方法都必须实施:
public interface ICommand
{
void execute();
void undo();
void store();
void load();
}
public class ManagerMacro : ICommand
{
List<ICommand> Commands;
Stack commandStack;
/// <summary>
/// Use in combination with AddSteps
/// </summary>
//public ManagerMacro()
//{
//}
public ManagerMacro(List<ICommand> commands)
{
this.Commands = commands;
this.commandStack = new Stack();
}
#region ICommand Members
public void execute()
{
for (int i = 0; i < Commands.Count; i++)
{
commandStack.Push(Commands[i]);
Commands[i].execute();
}
}
public void undo()
{
for (int i = 0; i < Commands.Count; i++)
{
if (commandStack.Count > 0)
{
ICommand Command = (ICommand)commandStack.Pop();
Command.undo();
}
}
}
public void store()
{
throw new NotImplementedException();
}
public void load()
{
throw new NotImplementedException();
}
#endregion
public void AddSteps(Steps[] steps)
{
foreach (Steps step in steps)
{
ICommand thisStep = null;
switch (step)
{
case Steps.Manager1: thisStep = new Step1(); break;
case Steps.Manager2: thisStep = new Step2(); break;
case Steps.Manager3: thisStep = new Step3(); break;
case Steps.Manager4: thisStep = new Step4(); break;
}
this.Commands.Add(thisStep);
}
}
}
请注意,我也使用工厂模式。