4

これは何よりもアーキテクチャ/ベスト プラクティスに関する質問なので、遠慮なく 2 セント追加してください。タイトルにステータスを記載したことは知っていますが、これはオブジェクトの基本的なプロパティに当てはまります。以下のアカウントの例は、私の質問をステータスよりも少しよく示すのに役立つと思います.

サンプルの Account オブジェクトを次に示します。

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) 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 メソッドに渡します。次に、関数は履歴マネージャーを使用してレコードを作成できます。

わかりました、この投稿は十分に長いです。私が十分に明確でない場合は、私に知らせてください。ご入力いただきありがとうございます。

4

3 に答える 3

10

あなたの方法はうまくいくかもしれませんが、別の方法を提案させてください。

Account クラスに TransactionAdded イベントを追加してみませんか。

次に、イベントが発生するたびに新しい AccountHistory オブジェクトが追加されるように、HistoryGroup オブジェクトからイベントをサブスクライブできます (ここでは推測しています)。

アップデート

コメントで述べたように、目標を達成する別の方法は、HistoryGroup にインターフェイス (ITransactionLogger など) を実装させてから、Account を変更して ITransactionLogger 依存関係を注入できるようにすることです。

これらのルートのいずれかに進むと、複雑さとデバッグの観点から管理が少し簡単になりますが、イベントのような複数のロガーは許可されません。

これにより、コードが少し柔軟になり、同時に、TransactionAdded イベントに関心のある他のコンシューマーがサブスクライブできるようになります。

于 2010-07-13T16:25:37.307 に答える
2

ジャスティンの答えにはいくつかの点で同意しますが、OP のタグの 1 つは POCO です。Account クラスにイベントを追加すると、何らかの方法で POCO が非 POCO になります。

AOP などに興味がある場合は、インターセプション (Unity や Castle を含むほとんどの IoC フレームワークがこの機能を提供します) を使用して、対象のトランザクションを取得できます。

インターセプトの利点は、 Account クラスが AccountHistory クラスとまったく結合していないことです。インターセプトは、必要なルールに従って高度に構成可能であり、アプリケーションの再コンパイルを強制することなく簡単に変更できます (AccountHistory を別のアセンブリに配置した場合)インターセプト ハンドラ)。インターセプトを使用することで、インフラストラクチャ タスク (監査) と見なされる可能性のあるものではなく、ビジネス ドメインにコードを集中させることができます。

繰り返しますが、これはツールボックスの別の代替手段です。なんらかの理由で POCO を有線でシリアル化する必要がない場合は、ジャスティンが提案するように、イベントを介してオブザーバー パターン (GoF) を実装する方が軽量なアプローチになる可能性があります。

于 2010-07-13T16:39:36.347 に答える
1

4人組はそう思っているようです。トランザクション、履歴の追跡、および元に戻すことはすべて、コマンドパターンコントラクトの一部です。スタックを使用して履歴を実装できます。コントラクトを含む関連コードのスニペットを次に示します。すべてのメソッドが実装されている、または実装されている必要があるわけではないことに注意してください。

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);
        }
    }
}

ファクトリパターンも使用していることに注意してください。

于 2010-07-13T16:48:46.277 に答える