3

次の設計上の問題に取り組む方法に関する推奨事項を探しています(stackoverflowに基づく架空の例を使用)。私は貧血のドメインモデルを避け、このタイプのケースに対する一般的な「ベストプラクティス」のアドバイスを求めたいと思います。

シナリオ:

質問が10の賛成票を受け取るたびに、質問の所有者に電子メール通知を送信するstackoverflowの新機能が開発されているとします。

ドメインオブジェクトモデルは次のようなものです。

public class Question
{
    string Question { get; set; }
    IList<Votes> Upvotes { get; set; }
    User Owner { get; set; }

    public void AddUpvote(Vote upvote)
    {
        Upvotes.Add(upvote);
    }
}

潜在的な実装:

  1. パラメータを取得し、メソッド内でロジックを実行するように変更AddUpvote()します。IEmailerServiceAddUpvote()

    public void AddUpvote(Vote upvote, IEmailerService emailer)
    {
        Upvotes.Add(upvote);
        if ( Upvotes.Count == 10 )
        {
            emailer.Send(Owner.EmailAddr);
        }
    }
    
  2. 内でこの状態を検出し、(IEmailerServiceをパラメーターとして渡す代わりに)IoCコンテナーからIEmailServiceAddUpvote()を解決します。AddUpvote()

  3. を呼び出す外部サービスオブジェクトでこの状態を検出しますquestion.AddUpvote()

    public void UpvoteClickHandler(Question question)
    {
        question.AddUpvote(new Upvote());
        if ( question.Upvotes.Count == 10 )
        {
            _emailer.Send(question.Owner.EmailAddr);
        }
    }
    
  4. ここであなたのより良い解決策!

4

4 に答える 4

5

関心の分離があるため、これら2つを混在させたくはありません。質問クラスに質問を気にさせ、メッセージサービスに投票が10、20、100、または...に達したときに何をすべきかを気にさせます。

次の例はデモンストレーションのみを目的としていますが、要点を理解できます。関心の分離が明確になっているため、メッセージ送信の要件が変更されても、Questionクラスを変更する必要はありません。SOLIDの原則によれば、クラスを変更する理由は1つだけであることを忘れないでください。

public class Question
{
    public string Description { get; set; }
    public Int32 Votes { get; set; }
    public User Owner { get; set; }

    public event EventHandler<QuestionEventArgs> OnUpvote;

    private void RaiseUpvoteEvent(QuestionEventArgs e)
    {
        var handler = OnUpvote;
        if (handler != null) handler(this, e);
    }

    public void Upvote()
    {
        Votes += 1;

        RaiseUpvoteEvent(new QuestionEventArgs(this));
    }
}

public class MessageService
{
    private Question _question;

    public MessageService(Question q)
    {
        _question = q;

        q.OnUpvote += (OnUpvote);
    }

    private void OnUpvote(object sender, QuestionEventArgs e)
    {
        if(e.Question.Votes > 10)
            SendMessage(e.Question.Owner);
    }
}

public class QuestionEventArgs: EventArgs
{
    public Question Question { get; set; }

    public QuestionEventArgs(Question q)
    {
        Question = q;
    }
}

だからあなたはそれを持っています。これを実現する方法は他にもたくさんありますが、イベントモデルは優れた方法であり、メンテナンスを早期に行うために、実装で必要な関心の分離を実現します。

于 2009-05-29T23:52:47.633 に答える
2

オプション1)と2)はどちらも、電子メールを送信するのに間違った場所であるとして飛び出します。Questionインスタンスは、次の2つのことを認識してはなりません。

  1. ポリシー、つまりいつ電子メールを送信するかについては知らないはずです。
  2. ポリシーの通知の仕組み、つまり電子メールサービスについては知らないはずです。

これは好みの問題であることは知っていますが、あなたは質問をポリシーと電子メールを送信するメカニズムの両方と密接に結び付けています。このQuestionクラスを別のプロジェクト(たとえば、StackOverflowの姉妹サイトであるServerFaultなど)に移動するのは非常に困難です。

作成しているヘルプデスクの通知システムを作成しているので、この質問に興味があります。これは私が私のシステムでしたことです:

NotificationManagerを作成します(基本的に、通知の問題を別のクラスに完全に移動します)。

public Class NotificationManager
{
    public void NotificationManager(NotificationPolicy policy, IEmailService emailer)
    {
    }
}

次に、これに沿って何かを行いました(UpvoteClickHandlerにはNotificationManagerインスタンスへの依存関係があります)。

public void UpvoteClickHandler(Question question)
{
    question.AddUpvote(new Upvote());
    _notificationManager.Notify(Trigger.UpvoteAdded, question);
}

UpvoteClickHandlerが行うのは、質問に賛成票が追加されたことをNotificationManagerに通知し、NotificationManagerに電子メールを送信するかどうかとその方法を決定させることだけです。

于 2009-05-29T23:39:37.753 に答える
1

答えは、アプリケーションとオブジェクトの設計に対する基本的なアプローチによって異なります。そして(ここで編集)あなたがシステムの最も重要な特徴として見ているもの。データ、質問、ビジネスルール、賛成票があるようです。オブジェクトにまったく質問しません。したがって、データをデータとして扱い、動作を混合しないことで、データツールがデータを処理できるようにする必要があります。従来のオブジェクト設計では、オブジェクト内のすべての動作とデータが含まれるため、電子メールの送信はオブジェクトに属します。(オプション1および2)これはブラックボックスまたは自己完結型オブジェクトアプローチだと思います。私が学んだように、現代の慣習には、単純なデータホルダーとしてのオブジェクトがあります。これは、移動、永続化、変換され、それらに何かが行われることを目的としています。おそらく、Cの構造体と同じくらい生きているのでしょう。

于 2009-05-29T23:48:40.403 に答える
1

こんにちは、みんな、

私の意見では、「質問が10の賛成票を受け取るたびに、質問の所有者に電子メール通知を送信する」はドメインロジックであり、したがって、貧血ドメインを回避するために、ドメインオブジェクトに含める必要があります。

インフラストラクチャ層に入る必要があるのは、電子メールを送信する(つまり、SMTPサーバーと通信する)アクションです。

したがって、オプション1は完全に間違っているわけではないと思います。IEmailerServiceのモック実装を渡すことで、いつでもオブジェクトをテストできることに注意してください。

よろしくお願いします、

ステファノ

于 2009-07-28T11:03:20.917 に答える