2.DAO의 분리
2-1. 관심사의 분리
- 개발자가 객체를 설계할 때 가장 염두에 둬야 할 사항은 바로 미래의 변화를 어떻게 대비할 것인가이다.
- 객체지향 기술이 만들어내는 가상의 추상세계 자체를 효과적으로 구성할 수 있고, 이를 자유롭고 편리하게 변경, 발전, 확장시킬 수 있다는데 의미가 있다.
- 분리와 확장을 고려한 설계
- 변경이 일어날 때 필요한 작업을 최소화하고, 변경으로 인한 문제를 일으키지 않을 수 있다.
- 모든 변경과 발전은 한 번에 한 가지 관심사항에 집중해서 일어난다.
- 프로그래밍의 기초 개념중 관심사의 분리를 객체 지향에 적용해보면, 관심이 같은 것끼리는 하나의 객체 안으로 또는 친한 객체로 모이게 하고, 관심이 다른 것은 가능한 한 따로 떠렁져서 서로 영향을 주지 않도록 분리하는 것.
2-2. 커넥션 만들기의 추출
UserDao의 관심사항
- DB와 연결을 위한 커넥션을 어떻게 가져올까라는 관심
- 사용자 등록을 위해 DB에 보낼 SQL 문장을 담을 Statement를 만들고 실행.
문제
- add()메소드에 있는 DB커넥션을 가져오는 코드와 동일한 코드가 get() 메소드에 중복되어 있다.
중복 코드의 메소드 추출
- 중복된 DB 연결 코드를 getConnection()이라는 이름의 독립적인 메소드로 만든다.
public class UserDao {
/*중복된 코드를 독립적인 메소드로 만들어 중복 제거*/
private Connection getConnection() throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3306/tobi", "root", "1234");
return c;
}
public void add(User user) throws ClassNotFoundException, SQLException {
Connection c = getConnection(); // DB 연결이 필요할 때, getConnection()메소드 이용
...
}
public User get(String id) throws ClassNotFoundException, SQLException {
Connection c = getConnection();
...
}
}
정보 변경 사항이 발생하더라도 이제 getConnection()이라는 메소드 하나의 코드만 수정하면 된다.
변경 사항에 대한 검증: 리팩토링과 테스트
앞의 작업은 여러 메소드에 중복돼서 등장하는 특정 관심사항이 담긴 코드를 별도의 메소드로 분리한 것이다. 이 작업은 기능에 영향을 주지 않으면서 코드의 구조만을 변경했다. 이런 작업을 리팩토링(Refactoring)이라고 한다.
위에서 getConnection()이라고 하는 공통의 기능을 담당하는 메소드로 중복된 코드를 뽑아내는 것을 리팩토링에서는 메소드 추출(Extract method)기법이라고 부른다.
리팩토링
기존의 코드를 외부의 동장방식에는 변화 없이 내부 구조를 변경하여 재구성하는 작업 또는 기술
2-3. DB 커넥션 만들기의 독립
변화를 반기는 DAO 만들기.
상황
- UserDao를 구매하고자 하는 N, D 회사
- 각 회사는 다른 종류의 DB 사용, DB 커넥션을 가져오는데 있어서 독자적으로 만든 방법을 적용하고 싶음.
- UserDao를 구매 후에도 DB 커넥션을 가져오는 방법이 변경될 가능성이 있음.
- 소스코드를 제공하면 해결되지만, 소스코드를 제공하고 싶진 않음.
상속을 통한 확장
기존 UserDao 코드를 한 단계 더 분리한다.
- userDao에서 메소드의 구현 코드를 제거, getConnection()을 추상 메소드로 제작.
- 추상 클래스 UserDao를 N사와 D사에게 판매.
- 구입한 포탈사들은 UserDao 클래스를 상속하여 각각 NUserDao, DUserDao라는 서브클래스를 만든다.
- 서브클래스에서 UserDao에서 추상 메소드로 선언했던 getConnection() 메소드를 마음대로 구현할 수 있다.
상속을 통한 확장 방법이 제공되는 UserDao
public abstract class UserDao {
/*구현 코드는 제거되고 추상 메소드로 바뀌었다.
메소드의 구현은 서브클래스가 담당한다.*/
public abstract Connection getConnection() throws ClassNotFoundException, SQLException;
public void add(User user) throws ClassNotFoundException, SQLException {
Connection c = getConnection(); // DB 연결이 필요할 때, getConnection()메소드 이용
...
}
public User get(String id) throws ClassNotFoundException, SQLException {
Connection c = getConnection();
...
}
}
N사의 NUserDao
public class NUserDao extends UserDao{
@Override
public Connection getConnection() throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3306/tobi", "root", "1234");
return c;
}
}
슈퍼클래스에 기본적인 로직의 흐름(커넥션 가져오기, SQL 생성, 실행, 반환)을 만들고, 그 기능의 일부를 추상 메소드나 오버라이딩이 가능한 protected 메소드 등으로 만든 뒤 서브 클래스에서 이런 메소드를 필요에 구현해서 사용하도록 하는 방법을 디자인 패턴에서 템플릿 메소드 패턴(template method pattern)이라고 한다.
서브 클래스에서 구체적인 오브젝트 생성 방법을 결정하게 하는 것은 팩토리 메소드 패턴(Factory method pattern)이라고 부른다.
getConnection() 메소드에서 생성하는 Connection 오브젝트의 구현 클래스는 제각각이겠지만 UserDao는 Connection 인터페이스 타입의 오브젝트라는 것 외에는 관심을 두지 않는다. 그저 Connection 인터페이스에 정의된 메소드를 사용할 뿐이다.
문제점
이 방법은 상속을 사용한 것이 단점이다.
- 만약 UserDao가 다른 목적을 위해 상속을 하고 있다면?
- 자바는 클래스의 다중 상속을 허용하지 않는다.
- 상속을 통한 상하위 클래스의 관계는 생각보다 밀접하다.
- 상속관계는 두 가지 다른 관심사에 대해 긴밀한 결합을 허용한다.
- 확장된 기능인 DB 커넥션을 생성하는 코드를 다른 DAO 클래스에 적용할 수 없다.
- UserDao 외에 DAO 클래스들이 계속 만들어진다면, 상속을 통하여 만들어진 getCoonection()의 구현 코드가 매 DAO 클래스마다 중복돼서 나타나는 심각한 문제가 발생
'Server > Spring&Spring Boot' 카테고리의 다른 글
[토비의 스프링] 오브젝트와 의존관계 - 인터페이스, 책임의 분리 (0) | 2022.10.24 |
---|---|
[토비의 스프링] 오브젝트와 의존관계 - DAO의 확장 (0) | 2022.10.24 |
[토비의 스프링] 오브젝트와 의존관계 - 초난감 DAO (0) | 2022.10.24 |
[토비의 스프링] 스프링이란? (0) | 2022.10.23 |
[Spring] @PathVariable로 불러온 값을 JSP에서 사용하기 (0) | 2022.07.07 |