-
1장 오브젝트와 의존관계 (1.1 초난감 DAO ~ 1.2 DAO의 분리)Java & Spring/토비의 스프링 3.1 2021. 5. 13. 17:45반응형
1장 오브젝트와 의존관계
- 스프링의 핵심 철학 : 객체지향 프로그래밍
- 객체의 라이프 사이클과 관계에 집중
- 디자인 패턴, 리팩토링, 단위 테스트 등과 같은 설계와 지식을 요구
1.1 초난감 DAO
두 가지 이상의 관심을 포함하고 있거나, 중복되는 코드를 가지고 있는 경우 유지 / 보수에 어려움을 겪는다.
하기 예시 코드를 보면서 어떤 문제점이 있는지 생각해보자.
// ... import statement pubilc class UserDao { public void add(User user) throws ClassNotFoundException, SQLException { Class.forName("com.mysql.jdbc.Driver"); Connection c = DriverManger.getConnection("jdbc:mysql://localhost/springbook", "spring", "book"); PreparedStatement = c.preparedStatement("insert into user(id, name, password), values(?, ?, ?);"); // ...insert logic } public void get(String id) throws ClassNotFoundException, SQLException { ClassNotFoundException, SQLException{ Class.forName("com.mysql.jdbc.Driver"); Connection c = DriverManger.getConnection("jdbc:mysql://localhost/springbook", "spring", "book"); PreparedStatement = c.preparedStatement("select id, name, password from user where id = ?;"); // ... get logic } }
1.2 DAO의 분리
위의 예시는 현재는 userDao 안에 두 개의 메소드만 존재하지만, 메소드가 확장될 가능성이 높고, 다른 Dao 클래스들이 추가될 가능성이 매우 높다. 만약, MySQL에서 Oracle로 변경한다면?? 메소드 개수만큼 변경해야할 것이다.
변경이 일어날 때, 필요한 작업을 최소화 하기 위해서는 분리와 확장을 고려한 설계가 필요
관심사의 분리라는 의미는 관심이 같은 것끼리 하나의 객체 또는 관련 객체로 모이게하고, 관심이 다른 것은 최대한 떨어뜨려 영향을 주지 않도록 분리하는 것
위의 예시 코드를 살피면, 하나의 메소드에 세 가지 관심사항이 발견된다.
- DB와 연결을 위한 connection을 어떻게 가져오는가
- DB에 보낼 SQL 문장을 담을 Statement를 만들고 실행
- 작업이 종료된 이후 사용한 공유 리소스(Statement, Connection, ResultSet 등) 오브젝트를 닫아줘서 시스템에게 돌려주는 것
먼저, 첫번째 관심을 메소드 추출로 리팩토링을 해보자.
public Connection getConnection() { Class.forName("com.mysql.jdbc.Driver"); Connection c = DriverManger.getConnection("jdbc:mysql://localhost/springbook", "spring", "book"); return c; }
Connection을 얻어오는 관심을 분리했을 뿐인데, Connection과 관련된 변화에 대응할 수 있는 코드가 되었다.
변화에 대응할 뿐만 아니라, 상속을 통해 변화에 자유로운 확장 코드로 해보자.
public abstract class UserDao { public void add(User user) throws ClassNotFoundException, SQLException { Connection c = getConnection(); // ... logic } public User get(String id) throws ClassNotFoundException, SQLException { Connection c = getConnection(); // ... logic } public abstract Connection getConnection() throws ClassNotFundExecption, SQLException; }
public class NUserDao extends UserDao { public Connection getConnection() throws ClassNotFOundExpcetion, SQLException { // N 사 DB Connection 생성코드 } } public class DUserDao extends UserDao { public Connection getConnection() throws ClassNotFOundExpcetion, SQLException { // D 사 DB Connection 생성코드 } }
탬플릿 메소드 패턴(팩토리 메소드 패턴)을 통해 UserDao에 대한 수정 없이, DB 연결 기능을 새롭게 정의한 클래스를 만들 수 있는 코드가 되었다. 즉, Connection 타입 인터페이스의 오브젝트를 이용할 수 있는 어떤 DB 연결에도 손쉽게 확장할 수 있게 수정되었다.
UserDao는 getConnection 메소드에서 Connection 인터페이스 타입의 오브젝트를 반환한다는 것 외에는 관심을 두지 않음
UserDao를 상속받은 NUserDao와 DUserDao는 어떤 방법으로 Connection 객체를 만들어내고 기능을 제공할지에 관심을 둔다.
상속을 통해 관심이 다른 기능을 분리하고 필요에 따라 변화에 대응하도록 했지만, 여전히 단점이 존재한다.
- 상속을 통한 상하위 클래스의 관계가 밀접하다.
- 서브 클래스가 슈퍼클래스의 기능을 직접 사용할 수 있기때문에, 슈퍼클래스 내부의 변경이 있을 때는 모든 서브클래스를 함께 수정하거나 다시 개발해야할 수 있음
- 위의 경우, DB Connection을 생성하는 코드를 다른 DAO 클래스에 적용할 수 없다
- 다음 장에서 클래스 분리를 통해 DAO 클래스들이 이용할 수 있는 DB Connection을 해보자.
- 상속을 통한 상하위 클래스의 관계가 밀접하다.
용어 정리
- 자바빈
- 본래 비주얼 툴에서 조작 가능한 컴포넌트를 의미
- 최근에는 디폴트 생성자와 프로퍼티를 지닌 오브젝트를 가리킴
- 리팩토링
- 기능에 영향을 주지 않으면서 코드의 구조만 변경하는 행위
- 주로 견고함을 위해 내부 설계를 좋은 방향으로 최신화하면서 진행
- 메소드 추출
- 공통의 기능을 담당하는 메소드로 중복된 코드를 뽑아내는 행위
- 탬플릿 메소드 패턴
- 슈퍼클래스에 기본적인 로직의 흐름을 만들고, 기능의 일부를 추상 메소드 or Override가 가능한 protected 메소드 등으로 만든 뒤, 서브클래스에서 필요에 맞게 메소드를 구현해서 사용하도록 하는 디자인 패턴
- 상속을 통해 슈퍼클래스의 기능을 확장
- 변하지 않는 기능은 슈퍼클래스에 만들어두고, 자주 변경되어 확장할 기능은 서브클래스에서 만들도록 함
- 서브 클래스에서 선택적으로 Override할 수 있도록 만든 메소드를 Hook 메소드라고 함
- 스프링에서 애용되는 디자인 패턴
- 슈퍼클래스에 기본적인 로직의 흐름을 만들고, 기능의 일부를 추상 메소드 or Override가 가능한 protected 메소드 등으로 만든 뒤, 서브클래스에서 필요에 맞게 메소드를 구현해서 사용하도록 하는 디자인 패턴
- 팩토리 메소드 패턴
- 서브클래스에서 구체적인 오브젝트 생성 방법을 결정하게 하는 것
- 주로 인터페이스 타입으로 오브젝트를 리턴하므로 서브클래스에서 정확히 어떤 클래스의 오브젝트를 만들어 리턴할 지 슈퍼클래스는 알지 못함(관심 X)
- 서브클래스에서 오브잭트 생성 방법과 클래스를 결정할 수 있도록 미리 정의해둔 메소드를 팩토리 메소드라고 하고, 이를 통해 나머지 로직을 완성
- 슈퍼클래스의 기본 코드에서 독립시키는 방법
- 상속을 통해 기능을 확장
- 스프링에서 애용되는 디자인 패턴
반응형'Java & Spring > 토비의 스프링 3.1' 카테고리의 다른 글
2장) 2.3 개발자를 위한 테스팅 프레임워크 JUnit (0) 2021.06.01 2장) 2.1 USERDAOTEST 다시보기 ~ 2.2 USERDAOTEST 개선 (0) 2021.05.27 1장) 1.8 XML을 이용한 설정 ~ 1.9 정리 (0) 2021.05.27 1장) 1.6 싱글톤 레지스트리와 오브젝트 스코프 ~ 1.7 의존관계 주입(IoC) (2) 2021.05.21 1장) 1.3 DAO의 확장 ~ 1.5 스프링의 IoC (1) 2021.05.17 - 스프링의 핵심 철학 : 객체지향 프로그래밍