✅ 本記事の目的
本記事では、前回に続き Service層の設計をさらに強化し、以下を目指します:
- 複数のServiceで使える「共通基盤」の構築
- DI(依存性注入)を意識した柔軟でテストしやすい設計
- モック差し替えによるユニットテストの向上
🧩 1. なぜ共通基盤とDIが必要なのか?
✳️ 問題点(Before)
- Serviceクラスで同じような
DAO呼び出し
やログ出力
,例外変換処理
が重複しやすい - DAOを直に生成(new)しているため、テスト時に差し替えられない
- コードの再利用性・保守性が低下
✅ 解決策(After)
- 共通処理を
BaseService
やAbstractService
にまとめる - DAOやユーティリティを DI(依存性注入) で受け取る設計にする
- テスト時に Mock DAO へ差し替え可能に
🧩 2. Serviceインタフェース+実装クラスの設計パターン
// UserService.java(インタフェース)
public interface UserService {
User getUserById(int id);
}
java
コピーする
編集する
// UserServiceImpl.java(実装クラス)
public class UserServiceImpl implements UserService {
private final UserDao userDao;
// DI(依存性注入)を意識したコンストラクタ
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
@Override
public User getUserById(int id) {
return userDao.findById(id);
}
}
✅ ポイント
-
UserService インタフェースが外部公開契約
-
UserServiceImpl は内部の具体実装
-
DAOを「自分でnewせず、外から渡す(DI)」のがコツ
🧩 3. BaseServiceの共通処理を活用する
// BaseService.java(共通処理を持たせる)
public abstract class BaseService {
protected void log(String msg) {
System.out.println("[Service Log] " + msg);
}
protected RuntimeException wrapException(Exception e) {
return new RuntimeException("Service層例外:" + e.getMessage(), e);
}
}
// UserServiceImpl.java(継承して共通処理を活用)
public class UserServiceImpl extends BaseService implements UserService {
private final UserDao userDao;
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
@Override
public User getUserById(int id) {
try {
log("ユーザー取得開始");
return userDao.findById(id);
} catch (Exception e) {
throw wrapException(e);
}
}
}
🧪 4. DIによるユニットテストのしやすさ
// UserServiceImplTest.java(JUnitでMock DAOを差し替え)
public class UserServiceImplTest {
@Test
public void testGetUserById() {
// Mock DAOを渡す
UserDao mockDao = new UserDao() {
public User findById(int id) {
User u = new User();
u.setUserId(id);
u.setUsername("mockUser");
return u;
}
// 他のメソッドは未使用なので空実装でOK
};
UserService service = new UserServiceImpl(mockDao);
User result = service.getUserById(1);
assertEquals("mockUser", result.getUsername());
}
}
✅ ポイント
-
実際のDBを使わずに動作検証ができる
-
DIの設計にしておくことで、簡単にモック注入できる
🧩 5. DIフレームワークとの連携(将来的に)
💡 Spring導入時のイメージ
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
...
}
☑️ 将来Springなどを導入する際もDI設計にしておけば移行しやすい
✅ まとめ:Vol.10.x シリーズの設計がつながる
層 | 内容 |
---|---|
DTO | データの受け渡しモデル(Vol.10.1) |
DAO | DBとの直接のやり取り(Vol.10.2~10.3) |
Action | UI層との橋渡し(Vol.10.4) |
Service | ロジック集中・DAO統合(Vol.10.6~10.8) ←いまここ! |