-
1장) 1.3 DAO의 확장 ~ 1.5 스프링의 IoCJava & Spring/토비의 스프링 3.1 2021. 5. 17. 15:03반응형
1장 오브젝트와 의존관계
1.3 DAO의 확장
- 모든 오브젝트는 관심사가 바뀔 때마다 변경이 일어난다.
- 앞서 팩토리 메소드 패턴을 통해 변화의 성격이 다른 것을 분리해서, 서로 영향을 주지 않고 독립적으로 변경하도록 리팩토링을 했다.
- 이번 장에서는 상속관계가 아닌 완전한 독립 클래스로 만들어보자.
-
public class UserDao { private SimpleConnectionMaker; public UserDao() { simpleConnectionMaker = new SimpleConnectionMaker(); } public void add(User user) throws ClassNotFoundException, SQLEXception { Connection c = simpleConnectionMaker.makeNewConnection(); // ... } }
-
public class SimpleConnectionMaker { public Connection makeNewConnection() throws ClassNotFoundException, SQLException { Class.forName("com.mysql.jdbc.Driver"); Connection c = DriverManager.getConnection("", "", ""); return c; } }
- 코드를 확실하게 분리했지만, 기존 N사와 D사에 UserDao 클래스만 공급하고 DB 커넥션은 상속으로 확장해서 사용하던게 불가능해졌다.
-
- 위의 코드를 자유롭게 확장하려면 두 가지 문제를 해결해야 한다.
- 첫째는 SimpleConnectionMaker의 메소드
- Connection을 얻는 메소드의 네이밍을 통일해야한다. (다른 클래스에서 널리 이용하기 위함)
- 둘째는 DB 커넥션을 제공하는 클래스가 어떤 것인지를 UserDao가 구체적으로 알고있어야 한다는 점(불필요한 관심)
- UserDao가 바뀔 수 있는 정보(DB 커넥션을 가져오는 클래스)에 대해 많이 알고 있기 때문에 UserDao를 수정해야하는 경우가 발생한다.
- 첫째는 SimpleConnectionMaker의 메소드
- 인터페이스를 도입해서 두 클래스 간 추상적인 느슨한 연결고리를 만들어 주자.
- 인터페이스는 어떤 일을 하겠다는 기능만 정의해두고 구현 방법은 나타나 있지 않다.
-
public interface ConnectionMaker { public Connection makeConnection() throws ClassNotFoundException, SQLException; }
-
public class DConectionMaker implements ConnectionMaker { public Connection makeConnection() throws ClassNotFoundException, SQLException { // D사의 Connection 로직 } }
-
public class UserDao() { private ConnectionMaker connectionMaker; public UserDao() { connectionMaker = new DConnectionMaker(); } public void add(User user) throws ClassNotFoundException, SQLException { Connection c = connectionMaker.makeConnection(); } }
- 위의 코드로 인해 DB 접속 클래스를 다시 만든다고 해도 UserDao코드를 고칠일이 없어졌다.
- 하지만, 여전히 DConnection 클래스의 생성자를 호출해서 오브젝트를 생성하는 코드가 남아있어서 확장에 자유롭지 못하다.
- 관계설정 책임의 분리
- 위의 코드를 독립적인 확장에 자유롭게 하기 위해서는, UserDao와 UserDao가 사용할 ConnectionMaker의 특정 구현 클래스 사이의 관계를 설정해주는 것에 관한 관심을 분리해야한다.
- UserDao의 코든 코드는 ConnectionMaker 인터페이스 외에는 어떤 클래스와도 관계를 가져서는 안되게 해야, UserDao의 수정 없이 DB 커넥션 구현 클래스를 변경할 수 있다.
- 외부에서 만든 오브젝트를 전달받기 위해 메소드 파라미터나 생성자 파라미터를 이용하자.
-
public UserDao(ConnectionMaker connectionMaker) { this.connectionMaker = connectionMaker; }
- 생성자를 통해 connectionMaker 오브젝트를 받아 ConnectionMaker의 구현에 관심이 사라졌다.
- 원칙과 패턴
- SOLID 5 원칙 (객체지향 설계 5원칙)
- 단일 책임 원칙(The Single Responsibility Principle => SRP)
- 모든 클래스는 하나의 책임만 가져야하고, 그 책임을 완전히 캡슐화 해야한다.
- 개방 폐쇄 원칙(The Open Closed Priciple => OCP)
- 확장에는 열려있고 수정에는 닫혀야한다.
- 리스코프 치환 원칙(The Liskov Subsitution Principle => LSP)
- 자식 클래스는 언제나 부모 클래스를 대체할 수 있어야한다.
- 인터페이스 분리 원칙(The Interface Segregation Principle => ISP)
- 하나의 일반적인 인터페이스 보다는 여러 개의 구체적인 인터페이스로 구성해야한다.
- 의존관계 역전 원칙(The Dependency Inversion Principle => DIP)
- 의존 관계를 맺을 때는 구체적인 클래스보다 인터페이스나 추상 클래스와 관계를 맺어야 한다.(변화가 없는 것에 의존)
- 단일 책임 원칙(The Single Responsibility Principle => SRP)
- 높은 응집도와 낮은 결합도 (개방 폐쇄 원칙과 연관)
- 응집도가 높다
- 하나의 모듈, 클래스가 하나의 책임 또는 관심사에만 집중
- 변화가 일어날 때 해당 모듈에서 변하는 부분이 크다 (모듈의 많은 부분이 함께 바뀐다.)
- 결합도가 낮다.
- 책임과 관심사가 다른 오브젝트 or 모듈과는 느슨하게 연결된 형태를 유지하는 것이 바람직하다.
- 관계 유지에 최소한만 간접적인 형태로 제공하고, 나머지는 서로 독립적이고 알 필요도 없게 하라
- 결합도 = 하나의 오브젝트가 변경될 때, 관계를 맺고 있는 다른 오브젝트에게 변화를 요구하는 정도
- 응집도가 높다
- 전략 패턴
- 디자인 패턴의 꽃
- 자신의 기능 맥락(Context)에서, 필요에 따라 변경이 필요한 알고리즘을 인터페이스로 통째로 외부로 분리시키고, 이를 구현한 구체적인 알고리즘 클래스를 필요에 따라 바꿔 사용할 수 있게하는 디자인 패턴
- 위의 예시로 보면, UserDao가 전략 패턴의 Context에 해당
- SOLID 5 원칙 (객체지향 설계 5원칙)
1.4 제어의 역전(IoC)
- UserDao와 ConnectionMaker 구현 클래스의 오브젝트를 만드는 것과, 이 둘을 연결해서 사용하도록 관계를 맺어주는 관심을 예시에 추가해보자.
- 팩토리
- 객체의 생성 방법을 결정하고 만들어진 오브젝트를 돌려주는 오브젝트
-
public class DaoFactory() { public UserDao userDao() { return new UserDao(connectionMaker()); } public accountDao() { return new AccountDao(connectionMaker()); } private ConnectionMaker connectionMaker() { return new DConnectionMaker(); } }
- UserDao와 ConnectionMaker는 데이터 로직과 기술 로직(실질적 로직)을 담당하고, DaoFactory는 Application의 오브젝트를 구성하고 관계를 정의하는 책임(설계도 역할)을 하게 된다.
- 제어권 이전을 통한 제어 관계 역전
- 제어의 역전 => 프로그램의 제어 흐름 구조가 뒤바뀌는 것
- 일반적으로 main() 메소드와 같이 프로그램 시작 지점에서 다음에 사용할 오브젝트 결정 ~> 생성 ~> 메소드 호출 ~> 메소드 내부에서 다음에 사용할 것을 결정 ~> 호출 의 반복이다.
- 제어의 역전
- 오브젝트가 자신이 사용할 오브젝트를 스스로 선택하지도 생성하지도 않는다.
- 자신도 어떻게 만들어지고 어디서 사용되는지 알 수 없다.
- 엔트리 포인트를 제외한 모든 오브젝트는 위임받은 제어 권한을 갖는 특별한 오브젝트에 의해 결정되고 만들어진다.
- 프레임워크가 제어의 역전 개념이 적용된 대표 기술이다.
- 제어의 역전 => 프로그램의 제어 흐름 구조가 뒤바뀌는 것
1.5 스프링의 IoC
- 스프링의 핵심은 Bean Factory, Application Context
- 애플리케이션 컨텍스트와 설정정보
- bean
- 스프링이 제어권을 가지고 직접 만들고 관계를 부여하는 오브젝트
- 오브젝트 단위의 애플리케이션 컴포넌트
- 스프링 컨테이너가 생성과 관계설정, 사용 등을 제어해주는 제어의 역전이 적용된 오브젝트
- bean factory
- 빈의 생성과 관계설정 같은 제어를 담당하는 IoC 오브젝트
- 빈을 생성하고 관계를 설정하는 IoC의 기본 기능에 초점을 둘 때, bean factory 라는 명칭을 주로 활용(생성과 제어의 관점)
- Application Context
- 빈 팩토리를 확장한 IoC 컨테이너
- 애플리케이션 전반에 걸쳐 모든 구성요소의 제어 작업을 당당하는 IoC 엔진의 의미가 좀 더 부각됨(스프링이 지원하는 애플리케이션의 지원 기능을 포함한 의미)
- 보통, bean factory와 Application Context를 같게보고 어디에 초점을 두고 말하는지에 따라 다르게 부를 때도 있음
- bean
- 앞서 작성했던 DaoFactory를 스프링 빈 팩토리가 사용할 수 있는 설정정보로 만들어보자.
-
@Configuration // application context or bean factory가 사용할 설정정보라는 표시 public class DaoFactory { @Bean // 오브젝트 생성을 담당하는 IoC용 메소드라는 표시 public UserDao userDao() { return new UserDao(connectionMaker()); } @Bean public ConnectionMaker connectionMaker() { return new DConnectionMaker(); } }
- Test 코드에서 이를 활용할 때는, AnnotationConfigApplicationContext를 이용해서 Application Context 객체를 생성하고 getBean 메소드를 통해 UserDao를 불러오면 된다.
-
- Application Context의 동작 방식
- ApplicationContext 인터페이스를 구현하는데, 빈 팩토리가 구현하는 BeanFactory 인터페이스를 상속했으므로 일종의 Bean Factory이다.
- DaoFactory는 DAO 오브젝트 생성과 DB 오브젝트와 관계를 맺어조는 제한적인 역할을 하는데, Application Context는 IoC를 적용해서 관리할 모든 오브젝트에 대한 생성과 관계 설정을 담당한다.
- 즉, 클라이언트의 요청이 들어오면 application context에서 bean factory 조회/호출/등록 등을 통해 관리하고, 오브젝트를 넘겨준다.
- Application Context의 장점
- 클라이언트는 구체적인 팩토리 클래스를 알 필요가 없다.
- 애플리케이션 발전에 따라 오브젝트가 추가되어도 클라이언트가 직접 알 필요가 없다.
- 애플리케이션 컨텍스트는 종합 IoC 서비스를 제공해준다.
- 부가적인 기능과 빈이 사용할 수 있는 기반기술 서비스, 외부 시스템과의 연동 등을 컨테이너 차원에서 제공
- 애플리케이션 컨텍스트는 빈을 검색하는 다양한 방법을 제공한다.
- 클라이언트는 구체적인 팩토리 클래스를 알 필요가 없다.
용어 정리
- 설정정보 / 설정 메타정보
- IoC를 적용하기 위해 사용하는 메타정보, IoC 컨테이너에 의해 관리되는 애플리케이션 오브젝트를 생성하고 구성할 때 사용
- 애플리케이션의 형상 정보 / 청사진
- 컨테이너 or IoC 컨테이너
- IoC방식으로 빈을 관리한다는 의미에서 Application Context나 빈 팩토리를 컨테이너 or IoC 컨테이너라고 한다.
- IoC 컨테이너는 주로 빈 팩토리 관점에서 이야기하는 것, 그냥 컨테이너 or 스프링 컨테이너라고 할 때는 애플리케이션 컨텍스트를 가리키는 것
- 스프링 프레임워크
- IoC 컨테이너, 애플리케이션 컨텍스트를 포함해서 스프링이 제공하는 모든 기능을 통틀어 말할 때 주로 사용
반응형'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.1 초난감 DAO ~ 1.2 DAO의 분리) (1) 2021.05.13