49

一般的に、DDD とドメイン モデリングの経験が豊富な人からのガイダンスを探しているという一般的なシナリオがあります。

ブログ エンジンの構築を開始するとします。最初の要件は、記事が投稿された後、ユーザーがコメントを投稿できるようにすることです。これは問題なく開始され、次の設計につながります。

public class Article
{
    public int Id { get; set; }

    public void AddComment(Comment comment)
    {
        // Add Comment
    }
}

私のMVCコントローラーは次のように設計されています:

public class ArticleController
{
    private readonly IRepository _repository;

    public ArticleController(IRepository repository)
    {
        _repository = repository;
    }

    public void AddComment(int articleId, Comment comment)
    {
        var article = _repository.Get<Article>(articleId);
        article.AddComment(comment);
        _repository.Save(article);
        return RedirectToAction("Index");
    }
}

これですべてが正常に機能し、要件を満たしています。次のイテレーションでは、コメントが投稿されるたびに、ブログの作成者に通知メールを送信する必要があります。

この時点で、私が考えることができる2つの選択肢があります。1) アーティクルを変更して IEmailService を要求するか (ctor で?)、DI コンテナーへの静的参照から EmailService を取得します。

1a) かなり醜いようです。私のエンティティがサービスを認識しているドメイン モデル ルールに違反していると思いますか?

public class Article
{
    private readonly IEmailService _emailService;

    public Article(IEmailService emailService)
    {
        _emailService = emailService;
    }

    public void AddComment(Comment comment)
    {
        // Add Comment

        // Email admin
        _emailService.SendEmail(App.Config.AdminEmail, "New comment posted!");
    }
}

1b) また、醜いようですが、静的にアクセスされる構成済みの DI コンテナーが必要になりました。

public class Article
{
    public void AddComment(Comment comment)
    {
        // Add Comment

        // Email admin
        var emailService = App.DIContainer.Resolve<IEmailService>();
        emailService.SendEmail(App.Config.AdminEmail, "New comment posted!");
    }
}

2) IArticleService を作成し、AddComment() メソッドを記事エンティティ自体ではなくこのサービスに移動します。

このソリューションはよりクリーンだと思いますが、コメントを追加することは発見されにくくなり、作業を実行するには ArticleService が必要になります。AddComment は Article クラス自体に属する必要があるようです。

public class ArticleService
{
    private readonly IEmailService _emailService;

    public ArticleService(IEmailService emailService)
    {
        _emailService = emailService;
    }

    public void AddComment(Article article, Comment comment)
    {
        // Add comment

        // Email admin
        _emailService.SendEmail(App.Config.AdminEmail, "New comment posted!");
    }

}


public class ArticleController
{
    private readonly IRepository _repository;
    private readonly IArticleService _articleService;

    public ArticleController(IRepository repository, IArticleService articleService)
    {
        _repository = repository;
        _articleService = articleService;
    }

    public void AddComment(int articleId, Comment comment)
    {
        var article = _repository.Get<Article>(articleId);
        _articleService.AddComment(article, comment);
        _repository.Save(article);
        return RedirectToAction("Index");
    }
}

したがって、私は基本的に、ドメイン モデリングの経験が豊富な人からのアドバイスを求めています。より明白な解決策が見つからない場合は、お知らせください:)

サービスオプションは見つけにくいため、正直なところ、どちらのソリューションも一般的に嫌いです。ArticleService を利用できないと、記事のインスタンスにコメントを追加できなくなりました。また、AddComment は Article 型の明白なメソッドのように見えるため、あまり自然ではないように感じます。

とにかく、私は入力を読むのを楽しみにしています。前もって感謝します。

4

5 に答える 5

24

この特定の問題は、 Domain Eventでエレガントに解決できると思います。

于 2009-09-28T19:03:37.267 に答える
2

アーティクル コントローラが基本的にメッセージを渡したり、イベントを投稿したりすることを考えたことはありますか? 次に、「article-posted-event-listener」はそのメッセージを消費し、それに応じて応答します。特定のケースでは、電子メール通知機能がこれらのイベントをリッスンし、そのように構成されます。このように、記事投稿ビットは電子メール通知ビットについて何も知る必要はありません。

于 2009-09-28T19:02:54.653 に答える
1

この優れた質問を調べて、MSDN の Udiのドメイン モデル パターンの採用を読むようになりました。

HTH は他のユーザーを支援します。

私はこれと同じ質問をする方法を考え出そうとしましたが、何度か混乱してしまいました. あなたの質問は確かにそうではありません!ありがとう

于 2010-02-01T07:59:57.017 に答える
0

ドメイン イベントを使用せずに、Double Dispatch パターンを使用して、ドメイン サービス内に AddComment ロジックを配置できます。

これは次のようになります。

public class Article
{
    public void AddComment(Comment comment, IAddCommentProcessor commentProcessor)
    {
        commentProcessor.AddComment(this, comment);
    }
}

public interface IAddCommentProcessor
{
    void AddComment(Article article, Comment comment);
}

public class AddCommentAndEmailProcessor : IAddCommentProcessor
{
    private readonly _emailService;
    public AddCommentAndEmailProcessor(EmailService emailService)
    {
        _emailService = emailService;
    }

    public void AddComment(Article article, Comment comment)
    {
        // Add Comment

        // Email
        _emailService.SendEmail(App.Config.AdminEmail, "New comment posted!");
    }
}

public class ArticleController
{
    private readonly IRepository _repository;
    private readonly IArticleService _articleService;

    public ArticleController(IRepository repository, IArticleService articleService)
    {
        _repository = repository;
        _articleService = articleService;
    }

    public void AddComment(int articleId, Comment comment)
    {
        var article = _repository.Get<Article>(articleId);
        article.AddComment(comment, new AddCommentAndEmailProcessor(ServiceLocator.GetEmailService())); // Or you can use DI to get the Email Service, or any other means you'd prefer
        _repository.Save(article);
        return RedirectToAction("Index");
    }
}

必要に応じて、Article の AddComment にコメントの追加ロジックを保持し、代わりにドメイン サービスを CommentAdded() メソッドを使用して ICommentAddedProcessor のようなものにし、Article の AddComment に Comment と ICommentAddedProcessor を持たせることができます。

于 2014-03-31T19:27:48.510 に答える