일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- 재귀
- 달빛클럽 1기
- Algorithm
- 백준
- 노마드코더
- 달빛클럽
- 리액트
- 프로그래머스
- 완전탐색
- 자바
- 달빛클럽1기
- 인플레이션에서 살아남기
- 노마드코더 강의
- programmers
- SoftwareExpertAcademy
- SWEA
- React.js
- 경제공부
- ReactJS로 영화 웹 서비스 만들기
- Array
- BOJ
- Stack
- JPA
- 알고리즘
- dfs
- HashMap
- 달빛캠퍼스
- 카카오블라인드코딩테스트
- Java
- React
- Today
- Total
th42500의 TIL
[Spring] UserDao Factory 생성 본문
오늘은 지금까지 작성했던 UserDao 클래스에 Factory를 적용해봄으로써 역할과 책임에 따른 클래스 분리를 해보고자 한다.
❓ Factory란?
✔ 객체의 생성 방법을 결정하고 그렇게 만들어진 오브젝트를 돌려주는 것
✔ 오브젝트를 생성하는 쪽과 오브젝트를 사용하는 쪽의 역할과 책임을 깔끔하게 분리하려는 목적으로 사용
⚠ 해당 Factory는 디자인패턴에서 말하는 특별한 문제를 해결하기 위해 사용되는 추상 팩토리 패턴이나 팩토리 메소드 패턴과는 다르다는 것을 유의하자
📌 UserDao에 Factory 적용하기
그동안 인터페이스를 생성하여 DB 커넥션을 제공하는 클래스에 대한 구체적인 정보는 모두 제거할 수 있었으나, 아직 UserDao가 인터페이스 뿐만 아니라 구체적인 클래스까지 알고 있다는 문제점이 남아 있었다. 즉, 불필요한 의존관계가 남아있어 이를 해결해야 했다.
이번 단계에서는 UserDAO와 ConnectionMaker 구현 클래스의 오브젝트를 만드는 것과 그렇게 만들어진 두 개의 오브젝트가 연결돼서 사용할 수 있도록 관계를 맺어주고자 한다.
즉, UserDao가 어떤 ConnectionMaker 구현 클래스의 오브젝트를 이용할지를 스스로 결정하게 할 수 있도록 만들고자 한다.
[UserDao.java]
UserDao에서는 생성자를 통해 Connection을 생성하는 객체를 생성자를 통해 주입받아 사용한다.
package com.sping.dao;
import com.sping.domain.User;
import java.sql.*;
import java.util.List;
public class UserDao {
private ConnectionMaker connectionMaker; // ✨
public UserDao(ConnectionMaker connectionMaker) { // ✨
this.connectionMaker = connectionMaker;
}
public List<User> selectAll() {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
List<User> userList = null;
try {
conn = connectionMaker.getConnection();
pstmt = conn.prepareStatement("select * from users");
rs = pstmt.executeQuery();
while(rs.next()) {
User user = new User(rs.getString("id"), rs.getString("name"), rs.getString("password"));
userList.add(user);
}
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
ConnectionClose.close(conn, pstmt, rs);
}
return userList;
}
public User selectById(String sId) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
User user = null;
try{
conn = connectionMaker.getConnection();
pstmt = conn.prepareStatement("select id, name, password from users where id = ?");
pstmt.setString(1, sId);
rs = pstmt.executeQuery();
if(rs.next()) {
user = new User(rs.getString("id"), rs.getString("name"), rs.getString("password"));
}
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
ConnectionClose.close(conn, pstmt, rs);
}
return user;
}
public void add(User user) {
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = connectionMaker.getConnection();
pstmt = conn.prepareStatement("insert into users(id, name, password) values (?, ?, ?)");
pstmt.setString(1, user.getId());
pstmt.setString(2, user.getName());
pstmt.setString(3, user.getPassword());
pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
ConnectionClose.close(conn, pstmt);
}
}
public void deleteAll() {
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = connectionMaker.getConnection();
pstmt = conn.prepareStatement("delete from users");
pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
ConnectionClose.close(conn, pstmt);
}
}
public int getCount() {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
int cnt = 0;
try{
conn = connectionMaker.getConnection();
pstmt = conn.prepareStatement("select count(*) from users");
rs = pstmt.executeQuery();
if (rs.next()) {
cnt = rs.getInt(1);
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
ConnectionClose.close(conn, pstmt);
}
return cnt;
}
}
[UserDaoFactory.java]
UserDaoFactory 클래스를 통해 Connection을 매개변수로 가지는 UserDao 객체를 return할 수 있도록 한다.
해당 클래스는 UserDao와 ConnectionMaker 구현 클래스의 오브젝트 간 관계를 맺는 책임을 담당하는 코드로, 이전에는 UserDao 생성자에게 해당 책임을 맡게 하였다면 지금은 UserDao의 클라이언트에게 책임을 넘겨주게 되었다.
이런 방법은 객체지향 프로그래밍의 특성 중 하나인 다형성 덕분에 가능하게 된 것이다.
package com.sping.dao;
public class UserDaoFactory {
public UserDao awsUserDao() {
ConnectionMaker connectionMaker = new AWSConnectionMaker();
return new UserDao(connectionMaker);
}
}
[ UserDaoTest.java ]
구현하는 코드가 달라졌으니 UserDaoTest 역시 UserDaoFactory의 awsUserDao()를 통해 UserDao 객체를 생성할 수 있도록 코드를 변경해주자.
package com.sping.dao;
import com.sping.domain.User;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class UserDaoTest {
UserDao userDao;
@BeforeEach
void setUp() {
userDao = new UserDaoFactory().awsUserDao();
userDao.deleteAll();
}
@Test
@DisplayName("add기능 & select 테스트")
void addAndSelectById() {
User user = new User("0", "Soyeong", "1234");
userDao.add(user);
assertEquals("Soyeong", userDao.selectById("0").getName());
}
@Test
@DisplayName("데이터 개수 세기 테스트")
void getCount() {
assertEquals(0, userDao.getCount());
User user = new User("0", "Soyeong", "1234");
userDao.add(user);
assertEquals(1, userDao.getCount());
}
@Test
@DisplayName("deletAll 테스트")
void deleteAll() {
userDao.deleteAll();
assertEquals(0, userDao.getCount());
}
}
[ 테스트 결과 ]
테스트 결과 이전과 마찬가지로 잘 실행되는 것을 확인할 수 있다.
'Backend > Spring & SpringBoot' 카테고리의 다른 글
[Spring] uses unchecked or unsafe operations. 경고 (0) | 2022.12.07 |
---|---|
[Spring, JUnit] JUnit5를 적용한 UserDao Test 코드 작성 (0) | 2022.10.18 |
[Spring] JDBC API를 이용한 MySQL 연동 (Feat. DriverManager) (0) | 2022.10.18 |