아래 글은 토비의 스프링을 읽고 공부하였습니다.
목차
1. DAO
1) DAO vs DTO
2) DAO-관심사의 분리
2. DAO의 분리
1) 클래스의 분리
2) Interface의 도입
3) 관계설정 책임의 분리
2. 원칙과 패턴
1) 개방 폐쇄 원칙
2) 전략 패턴
1. DAO
1. DAO vs DTO
DAO에 대해 파악하기 위해 우리가 개발할 때 많이 사용하는 DTO 개념과 비교해보자!
DTO는 데이터를 운반하기 위한 틀이라면,
class Person {
private String name;
private int age;
}
DAO는 data에 접근하기 위한 객체로, DB 접근에 대한 로직과 비즈니스 로직(Service, Controller, Repository)을 분리하기 위해 사용한다. 사실 지금은 HikariCP(스프링부트에 기본으로 내장되어 있는 JDBC 데이터베이스 커넥션 풀링 프레임워크)를 사용하기 때문에 굳이 이 DAO를 만들어 사용하지 않는다.
2. DAO에서 알아보는 관심사의 분리
DAO의 핵심 기능은 '어떻게 데이터를 등록하고 가져올 것인가' 이다.
이 때 이런 가정을 해보자.DB를 연동하여 데이터를 가져오는데, N사에서는 Oracle DB를, D사에서는 Mysql DB를 각각 따로 쓴다. 이럴 경우, 어떻게 로직을 짜는 것이 좋을까?
우선 결론부터 말하면 핵심은 관심사의 분리이다. 관심사의 분리는 '미래에, 변화에 어떻게 잘 대비할 수 있을까?'라는 질문에 '분리와 확장을 고려한 설계'라는 답을 내놓는다. 아래와 같이 UserDao를 상속을 통한 확장(오버라이딩)으로 분리한다.
코드로 살펴보면 아래와 같다.
public abstract class UserDao {
//add, get 등의 다른 코드 생략
public abstract Connection getConnection() throws ClassNotFoundException, SQLException;
}
public abstract NUserDao extends UserDao {
public abstract Connection getConnection() throws ClassNotFoundException, SQLException{
// N사 DB connection 생성 코드
};
}
public abstract DUserDao extends UserDao {
public abstract Connection getConnection() throws ClassNotFoundException, SQLException{
// D사 DB connection 생성 코드
};
}
이처럼 상속받은 코드는 custom화하여 작성해준다.
이것을 우리는 팩토리메서드 패턴(모 클래스에서 객체들을 생성할 수 있는 인터페이스를 제공하지만, 자식 클래스들이 생성될 객체들의 유형을 변경할 수 있도록 하는 생성 패턴)이라고 말한다.
2. DAO의 분리
1. 클래스의 분리
이번에는 직관적으로 와닿을 수 있는 설명인데, 관심사가 다르고 변화의 성격이 다른 UserDao속 add, get (User를 추가하고 가져오는 함수이겠다) 와 DB connection을 맺는 로직을 완전히 분리할 것이다.
SimpleConnectionMaker라는 class를 새로 만들고 UserDao에서
public class UserDao {
private SimpleConnectionMaker simpleConnectionMaker;
public UserDao() {
simpleConnectionMaker = new SimpleConnectionMaker();
}
public void add(User user) throws ClassNotFoundException, SQLException {
Connection c = simpleConnectionMaker.makeNewConnection();
// .. get도 마찬가지 코드이다.
}
}
로 DB connection을 가져오면 끝이다!
그렇다면 위의 로직에서는 N사와 D사의 Connection을 자유롭게 맺을 수 있을까? 아직 자유로운 확장이 가능하지 않다. 먼저
1. connectionmaker의 makeNewConnection() 함수로 가져왔기 때문에 N사와 D사 모두 같은 함수 이름으로 가져와야 한다. 즉 D사 코드와 N사 코드가 의존적이다.
2. DB connection을 제공하는 클래스가 어떤 것인지를 UserDao가 구체적으로 알고 있어야 한다. "Connection c" 로 인스턴스 변수까지 정의해놓고 있어서 N사에서 다른 클래스를 구현하면 UserDao도 같이 수정되어야 한다.
2. Interface의 도입
클래스를 분리하면서도 확장까지 가능한 방법이 없을까? Interface는 중간에 추상적인 느슨한 연결고리를 만들어 이를 가능하게 한다.
UserDao에서는 그저 makeNewConnection(); 메서드를 호출하기만 하면 되고, Connection 타입의 오브젝트는 알아서 만들어 돌려줄 것이라고 기대할 수 있다.
public interface ConnectionMaker {
public Connection makeConnection() throws ClassNotFoundException, SQLException;
}
public class DConnectionMaker implements ConnectionMaker {
public Connection makeConnection() throws ClassNotFoundException, SQLException {
//D사의 독립적인 방법으로 Connection 생성
}
}
3. 관계설정 책임의 분리
이러면 자연스럽게, 그래 interface로 분리해줬어. 근데 D사를 쓸지 N사를 쓸지 그건 어떻게 결정해? 라는 생각을 자연스럽게 할 수 있다. UserDao가 어떤 ConnectionMaker 구현 클래스의 오브젝트를 이용하게 할지 결정하는 이 관심사를 분리하는 방법은 무엇일까?
이 관심사를 아예 UserDao를 사용하는 클라이언트에게 할당한다.
public class UserDaoTest {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
ConnectionMaker connectionMaker = new DConnectionMaker();
UserDao dao = new UserDao(connectionMaker);
//사용할 ConnectionMaker 타입의 오브젝트 제공
}
}
원칙과 패턴
위에서 말한 로직들을 한 단어로 설명할 수 있는 원칙과 패턴이다.
1. 개방 폐쇄 원칙
클래스나 모듈의 확장(DB 연결 방법)에는 열려있어야 하고 변경(User 자신의 핵심 기능을 구현한 코드)에는 닫혀 있어야 한다.
SOLID 의 법칙 중 O(OCP-The Open Closed Principle)에 해당한다.
이는 높은 응집도와 낮은 결합도라는 단어로도 설명할 수 있는데, 응집도가 높다는 것은 하나의 모듈, 클래스가 하나의 책임 또는 관심사에만 집중되어 있다는 것을 의미한다. 결합도가 낮다는 것은 하나의 변경이 발생할 때 마치 파문이 이는 것처럼 여타 모듈과 객체로 변경에 대한 요구가 전파되지 않는 상태를 말한다.
OCP를 이행하기 위해서는 다음과 같은 과정을 많이 따른다고 한다.
- 1. 먼저 변경(확장)될 것과 변하지 않을 것을 엄격히 구분한다.
- 2. 이 두 모듈이 만나는 지점에 추상화(추상클래스 or 인터페이스)를 정의한다.
- 3. 구현체에 의존하기보다 정의한 추상화에 의존하도록 코드를 작성 한다.
2. 전략 패턴
자신의 기능맥락(context)에서, 필요에 따라 변경이 필요한 알고리즘을 인터페이스를 통해 통째로 외부로 분리시키고, 이를 구현한 구체적인 알고리즘 클래스를 필요에 따라 바꿔서 사용할 수 있게 하는 디자인 패턴이다.
'BackEnd > JAVA\SPRING' 카테고리의 다른 글
[SPRING] DI와 XML을 이용한 설정 (0) | 2023.09.05 |
---|---|
[SPRING] IOC (0) | 2023.09.03 |
[OPEN SOURCE] FOSSLIGHT 오픈소스 기여 (0) | 2023.08.21 |
[SPRING+JAVA] Whisper API와 ChatGPT API 연동 (2) | 2023.06.29 |
[Spring] Spring으로 JWT 구현하기2 - Spring Security 라이브러리 (0) | 2023.02.11 |