객체지향설계
객체는 어떻게 설계돼야 하나, 어떤 단위로 만들어지고 어떤 과정으로 객체의 존재를 들어내는가
객체지향 설계는 미래의 변화에 대비할 수 있어야 한다.
관심사의 분리
중복 코드의 메소드 추출
메소드 여러개의 중복되는 코드가 있다면 이를 하나의 메소드로 만들어주자.
ex) userDAO의 db랑 연결하는 코드가 메소드마다 있음
db종류 바뀐다거나, url이 바뀐다거나 등의 이슈 -> 모든 메소드의 코드를 다 바꿔야 함
db연결 메소드 getConnection()이란 메소드를 만들어서 다른 메소드에서 이를 호출하도록 변경
public void add(User user) throws ClassNotFoundException, SQLException {
Connection c = getConnection();
...
}
public User get(String id) throws ClassNotFoundException, SQLException {
Connection c = getConnection();
...
}
private Connection getConnectionO throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
Connection c = DriverManager.getConnection(
"jdbc:mysql://localhost/springbook", "spring", "book");
}
리팩토링
: 변경사항에 대한 검증
테스트를 통해 기능이 유지되는지 검증할 수 있다.
상속을 통한 확장
public abstract class UserDao {
public void add(User user) throws ClassNotFoundException, SQLException {
Connection c = getConnection();
}
public User get(String id) throws ClassNotFoundException, SQLException {
Connection c = getConnection();
}
public abstract Connection getConnection() throws ClassNotFoundException, SQLException;
public class AUserDao extends UserDao {
public Connection getConnection() throws ClassNotFoundException, SQLException {
// A 프로젝트 DB connection 생성코드
}
}
public class BUserDao extends UserDao {
public Connection getConnectionO throws ClassNotFoundException,
SQLException {
// B프로젝트 DB connection 생성코드
}
}
템플릿 메소드 패턴
상속을 통해 슈퍼클래스의 기능을 확장하기 위한 디자인 패턴
팩토리 메소드 패턴
서브클래스에서 구체적인 오브젝트 생성방법을 결정하게 하는것
상속의 문제점
오브젝트는 변한다. 변화에는 특징이 있다. 변화 마다 각기 대응 방식이 다르다
클래스의 분리
public class UserDaoTest {
public static void main(String[] args)
throws ClassNotFoundException, SQLException {
ConnectionMaker connectionMaker = new AConnectionMaker();
// A 프로젝트에서 사용하는 db연동
UserDao dao = new UserDao(connectionMaker);
// 구현 클래스 결정 -> 객체 생성
}
}
프로젝트 마다 사용하는 db가 다름 -> 같은 문제가 발생
인터페이스의 도입
관계설정 책임의 분리
클래스간의 관계를 설정하는 방법
원칙과 패턴
객체지향 설계를 위한 여러가지 방법
개방 폐쇄 원칙
기존코드를 수정하지 않고 기능을 추가할 수 있어야 한다.
높은 응집도와 낮은 결합도
전략패턴
blogRepository를 이용해 db연결에 따라 변경하도록 함
실제 구현한 알고리즘은 memoryBlogRepository로 분리
dbBlogReopsitory구현하여 필요에 따라 바꿔서 사용 가능
낮은 결합도를 활용하여 테스트, 유지관리를 더쉽게 하기 위한 설계 원칙
오브젝트 팩토리
팩토리 : 객체 생성 방법을 결정 -> 객체를 반환
public class DaoFactory {
public UserDao userDao() {
ConnectionMaker connectionMaker = new AConnectionMakerO; UserDao userDao = new UserDao(connectionMaker);
return userDao;
}
}
public class DaoFactory {
public UserDao userDao() {
return new UserDao(connectionMaker());
}
public AccountDao accountDaoO {
return new AccountDao(connectionMaker());
}
public MessageDao messageDaoO {
return new MessageDao(connectionMaker());
}
// ConnectionMaker를 생성하는 코드
// 중복을 피하기 위해 따로 메소드를 구현
public ConnectionMaker connectionMaker(){
return new AConnectionMaker();
}
}
제어의 역전이란?
프로그램의 제어 흐름 구조가 뒤바뀌는 것
오브젝트 팩토리를 이용한 스프링 IoC
빈(Bean) : 스프링이 제어권을 가지고 IoC 방식으로 직접 만들어 관계를 부여하는 객체
빈 팩토리 : 스프링에서 빈의 생성과 관계설정과 같은 제어를 담당하는 IoC 객체
애플리케이션 컨텍스트 : IoC 방식에 따라 만들어진 빈 팩토리,
스프링 컨테이너 : 빈 팩토리이자 애플리케이션 컨텍스트
의존관계 주입을 이용하여 애플리케이션을 구성하는 여러 빈들의 생명주기와 서비스 실행 등을 관리하며 생성된 인스턴스들에게 기능을 제공하는 것을 부르는 말이다.
설정정보/ 설정 메타정보 : 스프링 컨테이너를 적용하기 위해 사용하는 메타정보.
빈 팩토리라고 할 때는 빈을 생성하고 관계를 설정하는 IoC의 기본 기능 에 초점을 맞춘 것.
애플리케이션 컨텍스트는 별도의 정보를 참고해서 빈의 생성, 관계 설정 등의 제어를 총괄하는 것 에 초점을 맞춘 것
스프링 컨테이너의 동작방식
싱글톤 패턴
객체의 인스턴스를 한개만 생성되게 하는 패턴
서버 어플리케이션과 싱글톤
싱글톤의 한계
싱글톤 레지스트리
스프링은 싱글톤 패턴으로 객체를 생성하고 관리한다.
싱글톤과 오브젝트의 상태
멀티 스레드 환경에서 여러 스레드가 동시에 접근 할 수 있다.
스프링 빈의 스코프
객체가 생성되고 존재하고 적용되는 범위
싱글톤 스코프
그 외의 스코프
의존관계란?
A ----> B : A가 B에 의존하고 있다.
B의 변화가 A에 영향을 미친다.
ex)
blogService의 update() 파라미터가 바뀌면?
blogController에서 blogService.update()를 호출할 때 사용하는 파라미터가 바뀌어야 한다.
제어의 역전(IoC)과 의존관계 주입
IoC를 적용하여 객체지향적인 설계, 디자인 패턴, 컨테이너에서 동작하는 서버 기술을 사용한다.
의존관계 검색과 주입
메소드를 이요한 의존관계 주입
스프링 : '어떻게 오브젝트가 설계되고, 만들어지고, 어떻게 관계를 맺고 사용되는지에 관심을 갖는 프레임워크'
원칙을 잘 따르는 설계를 적용하려고 할 때 귀찮은 작업을 편하게 할 수 있도록 도와주는 유용한 도구
개발자 : 객체를 어떻게 설계하고, 분리하고, 개선하고, 어떤 의존관계를 가질지 결정.
스프링을 사용한다고 좋은 객체지향 설계와 깔끔하고 유연한 코드가 저절로 만들어지는건 절대 아님
좋은 글 감사합니다. 자주 올게요 :)