오브젝트와 의존관계
객체 지향 프로그래밍
객체 지향 프로그래밍은 유연하고 변경에 용이한 프로그램을 만들수 있다는 장점이 있다.
그러한 프로그램을 만들수 있도록 하는 객체지향의 특징 4가지와 원칙 5가지가 있다.
관심사의 분리 (Separation of Concerns)
- 컴퓨터 프로그램을 구별된 부분으로 분리하는 것
- 객체지향에서는 관심이 같은 것끼리는 하나의 객체 안으로 또는 친한 객체로 모이게 하고 관심이 다른 것은 가능한 한 따로 덜어져서 서로 영향을 주지 않도록 분리하는 것
public class UserDao {
public void add(User user) throws SQLException, ClassNotFoundException {
Class.forName("org.postgresql.Driver");
String user = "postgres";
String password = "password";
Connection c = DriverManager.getConnection(
"jdbc:postgresql://localhost/toby_spring"
, user
, password
);
PreparedStatement ps = c.prepareStatement(
"insert into users(id, name, password) values (?, ?, ?)"
);
ps.setString(1, user.getId());
ps.setString(2, user.getName());
ps.setString(3, user.getPassword());
ps.executeUpdate();
ps.close();
c.close();
}
public User get(String id) throws SQLException, ClassNotFoundException {
Class.forName("org.postgresql.Driver");
String user = "postgres";
String password = "password";
Connection c = DriverManager.getConnection(
"jdbc:postgresql://localhost/toby_spring"
, user
, password
);
PreparedStatement ps = c.prepareStatement(
"select * from users where id = ?"
);
ps.setString(1, id);
ResultSet rs = ps.executeQuery();
rs.next();
User user = new User();
user.setId(rs.getString("id"));
user.setName(rs.getString("name"));
user.setPassword(rs.getString("password"));
rs.close();
ps.close();
c.close();
return user;
}
- 중복 코드의 메소드 추출
/*
* 중복된 코드를 독립적인 메소드로 만들어서 중복을 제거한다.
*/
private Connection getConnection() throws ClassNotFoundException, SQLException {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection c = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:testDB" , "otep", "otep");
return c;
}
- 상속
템플릿 메소드 패턴
슈퍼 클래스에 기본적인 로직의 흐름을 만들고, 그 기능의 일부를 추상 메소드나 오버라이딩이 가능한 protected 메소드 등으로 만든 뒤 서브클래스에서 이런 메소드를 필요에 맞게 구현해서 사용하도록 하는 방법
팩토리 메소드 패턴
서브 클래스에서 구체적인 오브젝트 생성 방법을 결정하게 하는 것을 팩토리 메소드 패턴 이라고 부른다.
- 인터페이스
public class UserDao {
private ConnectionMaker connectionMaker;
public UserDao {
connectionMaker = new DConnectionMaker();
}
}
- 관계설정 책임의 분리
public class UserDao {
private ConnectionMaker connectionMaker;
public UserDao(ConnectionMaker connectionMaker) {
this.connectionMaker = connectionMaker;
}
}
package one;
import java.sql.SQLException;
public class Main {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
UserDao userDao = new UserDao(new DConnectionMaker());
// test code ...
}
}
다형성 : 역할과 구분을 분리 다형성 만으로는 좋은 객체지향 프로그래밍을 지킬 수 없음 → OCP 위반 (결국 구현 객체를 변경할 때 클라이언트 코드도 함께 변경됨.) IOC가 필요
제어의 역전(IoC : Inversion of Control)
구현 객체를 변경할때 클라이언트 코드도 같이 변경된다는 문제점이 있음
클라이언트 코드에 떠넘긴 책임을 분리시켜주자.
- 오브젝트 팩토리
// DaoFactory
package one;
public class DaoFactory {
public UserDao userDao() {
UserDao userDao = new UserDao(getConnectionMaker());
return userDao;
}
private ConnectionMaker getConnectionMaker() {
ConnectionMaker connectionMaker = new DConnectionMaker();
return connectionMaker;
}
}
// UserDao client main method
package one;
import java.sql.SQLException;
public class Main {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// UserDao userDao = new UserDao(new DConnectionMaker());
UserDao userDao = new DaoFactory().userDao();
// test code ...
}
스프링의 IOC
스프링 IoC의 장점
- 클라이언트는 구체적인 팩토리 클래스를 알 필요가 없다
- 애플리케이션 컨텍스트는 종합 IoC 서비스를 제공해준다
- 애플리케이션 컨텍스트는 빈을 검색하는 다양한 방법을 제공해준다
애플리케이션 컨텍스트
- 오브젝트 팩토리 == 애플리케이션 컨텍스트 == IOC 컨테이너 == DI 컨테이너
- @Configuration : 애플리케이션 오브젝트를 생성하고 구성할때 사용됨. 형상정보
- @Bean : 스프링이 관리하는 오브젝트
스프링에서는 스프링이 제어권을 가지고 직접 만들고 관계를 부여하는 오브젝트를 빈(Bean)
이라고 부른다. 그리고 스프링에서는 빈의 생성과 관계설정 같은 제어를 담당하는 IoC 오브젝트를 빈 팩토리(Bean Factory)
라고 한다. 보통 빈 팩토리보다는 이를 좀 더 확장한 애플리케이션 컨텍스트(application context)
라고 한다.
싱글톤 레지스트리
- 애플리케이션 컨텍스트는 싱글톤을 저장하고 관리하는 싱글톤 레지스트리
- 스프링 = 자바 엔터프라이즈 기술을 사용하는 서버환경
- 내부 구조가 복잡하고 많은 요청을 처리해야함. → 싱글톤이 아니면 매 요청마다 새로운 오브젝트가 생성되고 서버에 부하가 심해짐
싱글톤 패턴의 한계
- private 생성자를 갖고 있기 때문에 상속할 수 없다
- 싱글톤은 테스트하기 힘들다
- 서버환경에서는 싱글톤이 하나만 만들어지는 것을 보장하지 못한다
-
싱글톤의 사용은 전역 상태를 만들 수 있기 때문에 바람직하지 못하다
-
DI
## 의존관계 주입(DI : Dependency Injection)
### 의존관계
- 인터페이스에 의존 → 느슨한 결합(변화에 영향을 덜 받음 → 결합도 낮음)
- UserDao → «interface» ConnectionMaker ← DConnectionmaker
- DConnectionmaker ← 의존 오브젝트 : UserDao 오브젝트가 만들어지고나서 런타임 시에 의존관계를 맺는 대상, 즉 실제 사용대상인 오브젝트
### 의존관계 검색과 주입
public UserDao() { DaoFactory daoFactory = new DaoFactory(); this.connectionMaker = daoFactory.connectionMaker(); }
위의 코드는 IoC 개념을 따르고 있는 코드일까?
- UserDao는 어떤 의존 오브젝트를 사용할지 모른다(여전히 코드의 의존대상은 인터페이스)
- 스스로 IoC컨테이너인 DaoFactory에게 요청하고 있음.
- 이러한 방식을 의존관계 검색(Dependency lookup)이라고 함
### 의존관계 주입의 응용
- 기능 구현의 교환
- 부가기능 추가
### 메소드를 이용한 의존관계 주입
- 수정자 메소드를 이용한 주입
- 일반 메소드를 이용한 주입
IOC에 대해 설명해주세요.
-
답변
제어의 역전(IoC)란 모든 객체에 대한(생성, 라이프사이클 등) 제어권을 개발자가 아닌 IoC 컨테이너에게 넘긴 것을 말합니다.
스프링에서는 IoC 컨테이너에 객체들을 생성하면 객체끼리 의존성을 주입(DI, Dependency Injection)하는 역할을 하고
컨테이너에 등록한 객체들을 ‘빈’이라고 합니다.
스프링에서 빈(Bean)을 등록하는 방법에 대해 말해보세요.
-
답변
빈을 등록하는 방법은 기본적으로 2 가지가 있습니다.
-
우선 가장 쉬운 방법으로 @Component 어노테이션을 사용하는 것입니다.
@Controller, @Service, @Repository는 모두 @Component를 포함하고 있습니다.
-
설정 클래스를 따로 만들어 @Configuration 어노테이션을 붙이고,
해당 클래스 안에서 빈으로 등록할 메소드를 만들어 @Bean 어노테이션을 붙여주면 자동으로 해당 타입의 빈 객체가 생성됩니다.
-
Leave a comment