16

ActiveRecord を使用すると、次のようなクラスを定義できます。

class Contact
{
  private String _name;
  public String Name
  {
    get { return _name; }
    set 
    { 
      if (value == String.IsNullOrWhiteSpace())
        throw new ArgumentException(...);
      else
        _name = value;
    }
  }

  public Boolean Validate() { ... /* check Name is unique in DB */  }

  public Boolean Save() { ... }

  public static List<Contact> Load() { ... }
}

これは素晴らしくシンプルですが、ロジックが大きく混ざり合っているため、クラスが非常に肥大化していることがわかりました。

階層化/ドメイン設計を使用すると、次のような同じクラスを定義できます。

class Contact
{
    [Required(AllowEmptyStrings=false)]
    public String Name { get; set; }
}

class ContactService : IService
{
    public List<Contact> LoadContacts() { return (new ContactRepository()).GetAll(); }
    public Contact LoadContact(int id) { return (new ContactRepository()).GetById(id); }
    public Boolean SaveContact(Contact contact)
    {
        if (new ContactValidator().Validate(contact))
            new ContactRepository().Save(contact);
    }
}

class ContactRepository : IRepository
{
    public List<Contact> GetAll() { ... }
    public Contact GetById(int Id) { ... }
    public Boolean Save(Contact contact) { ... }
}

class ContactValidator : IValidator
{
    public Boolean Validate(Contact contact) { ... /* check Name is unique in DB */ }
}

class UnitOfWork : IUnitOfWork
{
    IRepository _contacts = null;
    public UnitOfWork(IRepository contacts) { _contacts = contacts; }
    public Commit() { _contacts.Save(); }
}

Active Record => レイヤード デザインからどのように移行されましたか?

  • Name セッターでのエンティティ レベルの検証 => そのまま (DataAnnotation 経由で可能)
  • ビジネス ロジック/ルールの検証 (一意の名前) => エンティティから新しい別の ContactValidator に移動
  • 保存ロジック => 別のリポジトリ パターン クラスに移動 (UnitOfWork も使用)
  • ロード ロジック => 別のリポジトリに移動
  • リポジトリとの対話は、新しい ContactService を介して行われます (これにより、ContactValidator、ContactRepository、UnitOfWork などの使用が強制されます。発信者が ContactRepository を解放するのとは対照的です!)。

この階層化されたデザインのピア承認/提案を探しています - 通常、アクティブ レコード タイプ以外のデザインはしません! コメントをいただければ幸いです。

注意 - この例は意図的に単純化されています (UnitOfWork は実際には使用されず、Repository/Validator の新規作成は別の方法で処理されます)。

4

3 に答える 3

11

それは、ドメイン ロジックの複雑さに大きく依存します。たとえば、単純なブログを書いている場合、アクティブなレコードは問題なく、ほとんどのアプリケーションはデータの保存と読み込みを行っています。そのシンプルでアクティブなレコード パターンは、ジョブに最適なツールです。

ただし、複雑なビジネス ルールやプロセスが多数ある海運会社向けにソフトウェアを作成していた場合、リポジトリ パターンを他のドメイン駆動設計パターンと共に使用すると、長期的にははるかに保守しやすいコードが提供されます。

ドメイン駆動設計を使用すると、仕様パターンを使用して検証を実現できます。

于 2011-08-25T02:32:41.787 に答える
4

この記事は、両方の優れた簡潔な説明のようです :

私が付け加えたいことの 1 つは、「永続化のニーズが単純な場合はアクティブ レコードが適切であり、永続化のニーズが複雑な場合はリポジトリが適切である」だけではないということです。ここでのパターンの選択は、デメテルの法則についてどのように感じるかに大きく関係しています. アーキテクチャのさまざまな部分を完全に分離して、誰かが別の部分を理解せずに 1 つの部分を理解できるようにしたい場合は、デメテルの法則が必要です。とはいえ、特にプロジェクトの早い段階で仕様が変更される可能性が高い場合、この種の抽象化に執着しすぎるのは非常に危険だと思います。あなたのプロジェクトの将来のメンテナーを推測しないでください。彼らは賢いかもしれませんし、一度に複数のことを考えることができるはずです。

于 2018-02-01T14:51:38.297 に答える
3

どちらのアプローチにも長所と短所があります。

ふりをして、Active Record スタイルのオブジェクトをどこか (BL の奥深く) に渡します。読むことも、変更することも、保存することもできます。この場合、BL のその部分はエンティティのインターフェイスとのみ結合されます。階層化されたアーキテクチャでは、何らかの方法でリポジトリをそのコードに渡す必要があります。明示的に渡すか、IoC コンテナーを使用するかは、あなた次第です。

もう 1 つのポイントは、リポジトリの概念があれば、リポジトリ内の新しいオブジェクトがある、またはリポジトリから削除されたオブジェクトが 1 つあるなどの基本的な概念を簡単に定義できることです。分散環境で作業している場合、非常に便利な通知です。

于 2011-07-19T19:14:35.107 に答える