DAOについて

※この記事はChatGPTで検索した内容を元に作成しています。

---

DAO（Data Access Object）パターンは、データベースや永続化されたデータに対するアクセスを抽象化し、データ操作を行うためのインタフェースを提供するデザインパターンです。このパターンを使うことで、データベースに直接アクセスするコードをビジネスロジックから分離し、データ操作に関するコードの変更が必要になった場合にも、ビジネスロジックに影響を与えずに変更を行うことができます。

---

### DAOの目的
DAOパターンの主な目的は、アプリケーションのビジネスロジックとデータアクセスロジックを分離することです。これにより、次のような利点が得られます。

1. **メンテナンス性の向上**
   - データベースとのやり取りに関するコードが一箇所に集約されるため、データベースの変更（例えば、SQL文の修正やデータベースの種類の変更）をDAOクラスのみで行えるようになります。
   
2. **テストの容易さ**
   - ビジネスロジックからデータアクセス部分が独立しているため、モックを使ってDAOをテストしやすくなります。

3. **コードの再利用**
   - データ操作に関するロジックがDAOに集約されるため、他のクラスでも再利用できるようになります。

4. **柔軟性**
   - DAOパターンを使用することで、異なるデータベースや永続化技術に対して柔軟に対応できます。例えば、データベースからファイルシステムやWebサービスへの切り替えも比較的簡単に行えます。

---

### DAOパターンの構造

DAOパターンでは、主に次のコンポーネントが登場します。

1. **DAOインタフェース**
   - データ操作に必要なメソッドを定義するインタフェースです。例えば、CRUD操作（Create, Read, Update, Delete）のメソッドを定義します。

2. **DAO実装クラス**
   - DAOインタフェースを実装したクラスで、実際にデータベースに接続してデータ操作を行います。ここで、JDBCやORM（例えばHibernate）を使用してSQL文を実行します。

3. **モデルクラス（DTO/Entityクラス）**
   - データベースのテーブルに対応するオブジェクトを表すクラスです。DAOはこのモデルクラスを使って、データの読み書きを行います。

4. **サービスクラス（またはビジネスロジック）**
   - ビジネスロジックを持つクラスで、DAOを使用してデータの操作を行います。このクラスは、データベースの具体的な操作方法に依存せず、DAOのメソッドを呼び出すだけです。

---

### DAOパターンの例

以下は、簡単なJavaでのDAOパターンの実装例です。ここでは、`User` エンティティに対して基本的なCRUD操作を行うDAOを作成します。

#### 1. `User` モデルクラス

```java
public class User {
    private int id;
    private String name;
    private String email;
    
    // コンストラクタ、getter、setterなど
    public User(int id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }

    // GetterとSetter
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}
```

#### 2. DAOインタフェース

```java
import java.util.List;

public interface UserDao {
    void insertUser(User user);  // Create
    User getUserById(int id);    // Read
    List<User> getAllUsers();    // Read
    void updateUser(User user);  // Update
    void deleteUser(int id);     // Delete
}
```

#### 3. DAOの実装クラス

```java
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class UserDaoImpl implements UserDao {

    private Connection connection;

    // コンストラクタでDB接続を初期化
    public UserDaoImpl(Connection connection) {
        this.connection = connection;
    }

    @Override
    public void insertUser(User user) {
        try {
            String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
            PreparedStatement statement = connection.prepareStatement(sql);
            statement.setString(1, user.getName());
            statement.setString(2, user.getEmail());
            statement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Override
    public User getUserById(int id) {
        User user = null;
        try {
            String sql = "SELECT * FROM users WHERE id = ?";
            PreparedStatement statement = connection.prepareStatement(sql);
            statement.setInt(1, id);
            ResultSet rs = statement.executeQuery();
            if (rs.next()) {
                user = new User(rs.getInt("id"), rs.getString("name"), rs.getString("email"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return user;
    }

    @Override
    public List<User> getAllUsers() {
        List<User> users = new ArrayList<>();
        try {
            String sql = "SELECT * FROM users";
            Statement statement = connection.createStatement();
            ResultSet rs = statement.executeQuery(sql);
            while (rs.next()) {
                User user = new User(rs.getInt("id"), rs.getString("name"), rs.getString("email"));
                users.add(user);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return users;
    }

    @Override
    public void updateUser(User user) {
        try {
            String sql = "UPDATE users SET name = ?, email = ? WHERE id = ?";
            PreparedStatement statement = connection.prepareStatement(sql);
            statement.setString(1, user.getName());
            statement.setString(2, user.getEmail());
            statement.setInt(3, user.getId());
            statement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void deleteUser(int id) {
        try {
            String sql = "DELETE FROM users WHERE id = ?";
            PreparedStatement statement = connection.prepareStatement(sql);
            statement.setInt(1, id);
            statement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
```

#### 4. サービスクラス

```java
public class UserService {
    private UserDao userDao;

    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    public void createUser(String name, String email) {
        User user = new User(0, name, email); // IDはDB側で自動生成されると仮定
        userDao.insertUser(user);
    }

    public User getUser(int id) {
        return userDao.getUserById(id);
    }

    public List<User> getAllUsers() {
        return userDao.getAllUsers();
    }

    public void updateUser(User user) {
        userDao.updateUser(user);
    }

    public void deleteUser(int id) {
        userDao.deleteUser(id);
    }
}
```
---
### DAOパターンの利点
1. **データアクセスの一元化**：データベースアクセスのロジックがDAOに集約されるため、管理がしやすくなります。
   
2. **保守性の向上**：データベースの変更やSQL文の変更があっても、ビジネスロジックに影響を与えずに修正可能です。

3. **テスト容易性**：DAOのインタフェースに基づき、モックオブジェクトを使って簡単にテストを行えます。

4. **抽象化による柔軟性**：DAOパターンを使うことで、データベースの種類に依存しないアプリケーションを開発できます。
---
### まとめ
DAOパターンは、データベースや他の永続化システムとのやり取りを抽象化し、アプリケーションのビジネスロジックからデータ操作を分離するデザインパターンです。これにより、保守性、再利用性、柔軟性が向上し、大規模なアプリケーションの開発において非常に役立つパターンです。