1. 概要

多くの場合、リポジトリとDAOの実装は、特にデータ中心のアプリでは互換性があると見なされます。 これは、それらの違いについて混乱を引き起こします。

この記事では、DAOパターンとリポジトリパターンの違いについて説明します。

2. DAOパターン

データアクセスオブジェクトパターン、別名 DAOパターンは、データの永続性を抽象化したものであり、多くの場合テーブル中心のである基盤となるストレージに近いと見なされます。

したがって、多くの場合、DAOはデータベーステーブルと一致し、ストレージからデータを送受信するためのより簡単な方法を可能にし、醜いクエリを隠します。

DAOパターンの簡単な実装を調べてみましょう。

2.1. ユーザー

まず、基本的なUserドメインクラスを作成しましょう。

public class User {
    private Long id;
    private String userName;
    private String firstName;
    private String email;

    // getters and setters
}

2.2. UserDao

次に、Userドメインに簡単なCRUD操作を提供するUserDaoインターフェイスを作成します。

public interface UserDao {
    void create(User user);
    User read(Long id);
    void update(User user);
    void delete(String userName);
}

2.3. UserDaoImpl

最後に、UserDaoインターフェイスを実装するUserDaoImplクラスを作成します。

public class UserDaoImpl implements UserDao {
    private final EntityManager entityManager;
    
    @Override
    public void create(User user) {
        entityManager.persist(user);
    }

    @Override
    public User read(long id) {
        return entityManager.find(User.class, id);
    }

    // ...
}

ここでは、簡単にするために、 JPA EntityManagerインターフェースを使用して、基盤となるストレージと対話し、Userドメインにデータアクセスメカニズムを提供しました。

3. リポジトリパターン

EricEvansの著書Domain-DrivenDesignによると、「リポジトリは、オブジェクトのコレクションをエミュレートする、ストレージ、取得、および検索動作をカプセル化するためのメカニズムです。」

同様に、エンタープライズアプリケーションアーキテクチャのパターンによると、「ドメインオブジェクトにアクセスするためのコレクションのようなインターフェイスを使用して、ドメインとデータマッピングレイヤーの間を仲介します。」

つまり、リポジトリはデータも処理し、DAOと同様にクエリを非表示にします。 ただし、アプリのビジネスロジックに近い、より高いレベルにあります。

したがって、リポジトリはDAOを使用してデータベースからデータをフェッチし、ドメインオブジェクトにデータを取り込むことができます。 または、ドメインオブジェクトからデータを準備し、永続化のためにDAOを使用してストレージシステムに送信することもできます。

Userドメインのリポジトリパターンの簡単な実装を調べてみましょう。

3.1. UserRepository

まず、UserRepositoryインターフェイスを作成しましょう。

public interface UserRepository {
    User get(Long id);
    void add(User user);
    void update(User user);
    void remove(User user);
}

ここでは、オブジェクトのコレクションを操作するために、 get add update removeなどの一般的なメソッドをいくつか追加しました。 。

3.2. UserRepositoryImpl

次に、 UserRepositoryImpl クラスを作成して、 UserRepository インターフェイスの実装を提供します:

public class UserRepositoryImpl implements UserRepository {
    private UserDaoImpl userDaoImpl;
    
    @Override
    public User get(Long id) {
        User user = userDaoImpl.read(id);
        return user;
    }

    @Override
    public void add(User user) {
        userDaoImpl.create(user);
    }

    // ...
}

ここでは、 UserDaoImpl を使用して、データベースからデータを送受信しました。

これまでのところ、 User クラスは貧血のドメインであるため、DAOとリポジトリの実装は非常に似ていると言えます。 また、リポジトリは、データアクセス層(DAO)の単なる別の層です。

ただし、DAOはデータにアクセスするのに最適な候補のようであり、リポジトリはビジネスユースケースを実装するための理想的な方法です

4. 複数のDAOを使用したリポジトリパターン

最後のステートメントを明確に理解するために、Userドメインを拡張してビジネスユースケースを処理しましょう。

ユーザーのTwitterツイート、Facebook投稿などを集約して、ユーザーのソーシャルメディアプロファイルを作成したいとします。

4.1. ツイート

まず、ツイート情報を保持するいくつかのプロパティを使用してTweetクラスを作成します。

public class Tweet {
    private String email;
    private String tweetText;    
    private Date dateCreated;

    // getters and setters
}

4.2. TweetDaoおよびTweetDaoImpl

次に、 UserDao と同様に、ツイートをフェッチできるTweetDaoインターフェイスを作成します。

public interface TweetDao {
    List<Tweet> fetchTweets(String email);    
}

同様に、fetchTweetsメソッドの実装を提供するTweetDaoImplクラスを作成します。

public class TweetDaoImpl implements TweetDao {
    @Override
    public List<Tweet> fetchTweets(String email) {
        List<Tweet> tweets = new ArrayList<Tweet>();
        
        //call Twitter API and prepare Tweet object
        
        return tweets;
    }
}

ここでは、Twitter APIを呼び出して、ユーザーが自分のメールを使用してすべてのツイートを取得します。

したがって、この場合、DAOはサードパーティのAPIを使用したデータアクセスメカニズムを提供します。

4.3. ユーザードメインを強化

最後に、UserクラスのUserSocialMediaサブクラスを作成して、Tweetオブジェクトのリストを保持しましょう。

public class UserSocialMedia extends User {
    private List<Tweet> tweets;

    // getters and setters
}

ここで、 UserSocialMedia クラスは、Userドメインのプロパティも含む複雑なドメインです。

4.4. UserRepositoryImpl

次に、 UserRepositoryImpl クラスをアップグレードして、ツイートのリストとともに User ドメインオブジェクトを提供します:

public class UserRepositoryImpl implements UserRepository {
    private UserDaoImpl userDaoImpl;
    private TweetDaoImpl tweetDaoImpl;
    
    @Override
    public User get(Long id) {
        UserSocialMedia user = (UserSocialMedia) userDaoImpl.read(id);
        
        List<Tweet> tweets = tweetDaoImpl.fetchTweets(user.getEmail());
        user.setTweets(tweets);
        
        return user;
    }
}

ここで、 UserRepositoryImpl は、 UserDaoImpl を使用してユーザーデータを抽出し、TweetDaoImpl。を使用してユーザーのツイートを抽出します。

次に、両方の情報セットを集約し、ビジネスユースケースに便利なUserSocialMediaクラスのドメインオブジェクトを提供します。 したがって、リポジトリは、さまざまなソースからのデータにアクセスするためにDAOに依存しています

同様に、 User ドメインを拡張して、Facebookの投稿のリストを保持することができます。

5. 2つのパターンの比較

DAOとリポジトリのパターンのニュアンスを確認したので、それらの違いを要約してみましょう。

  • DAOは、データの永続性を抽象化したものです。 ただし、リポジトリはオブジェクトのコレクションを抽象化したものです
  • DAOは下位レベルの概念であり、ストレージシステムに近いものです。 ただし、リポジトリはより高いレベルの概念であり、ドメインオブジェクトに近いものです
  • DAOはデータマッピング/アクセスレイヤーとして機能し、醜いクエリを隠します。 ただし、リポジトリはドメインとデータアクセスレイヤーの間のレイヤーであり、データの照合とドメインオブジェクトの準備の複雑さを隠します
  • DAOはリポジトリを使用して実装することはできません。 ただし、リポジトリは、基盤となるストレージにアクセスするためにDAOを使用できます

また、貧血のドメインがある場合、リポジトリは単なるDAOになります。

さらに、リポジトリパターンはドメイン駆動設計を促進し、技術者以外のチームメンバーにもデータ構造を簡単に理解できるようにします

6. 結論

この記事では、DAOパターンとリポジトリパターンの違いについて説明しました。

まず、DAOパターンの基本的な実装について検討しました。 次に、リポジトリパターンを使用した同様の実装を確認しました。

最後に、複数のDAOを利用して、ビジネスのユースケースを解決するためにドメインの機能を強化するリポジトリについて説明しました。

したがって、アプリがデータ中心からビジネス指向に移行する場合、リポジトリパターンはより良いアプローチであると結論付けることができます。

いつものように、すべてのコード実装はGitHub利用できます。