Today I Learned_230227

3 분 소요

토비의 스프링 3.1

DAO의 확장

  • 관심사에 따라 분리한 오브젝트들은 각기 독특한 변화의 특징이 있음
  • 변화의 성격이 다르다는 것은 변화의 이유, 시기, 주기가 다르다는 것
  • 변화의 성격이 다른 것을 분리해서, 서로 영향을 주지 않은 채로 각각 필요한 시점에 독립적으로 변경할 수 있도록 해야 함

클래스의 분리

  • 관심사가 다른 것들을 독립적인 클래스로 분리
  • 독립 클래스로 분리하고 한 클래스가 다른 클래스를 사용하도록 분리
  • 예제 : 사용자 정보를 저장하고 가져오는 방법 / DB연결하고 커넥션을 가져오는 방법을 분리

DB연결 분리

public class SimpleConnectionMaker {
    public Connection makeNewConnection() throws  ClassNotFoundException, SQLException {
        Class.forName("jdbc 드라이버 이름");
        Connection c = DriverManager.getConnection("jdbc url", "user", "pwd");
        return c;
    }
}

사용자 정보 저장하고 가져오기

public class UserDao {
    private SimpleConnectionMaker simpleConnectionMaker;

    public UserDao(SimpleConnectionMaker simpleConnectionMaker) {
        this.simpleConnectionMaker = new SimpleConnectionMaker();
    }

    public void add(User user) throws  ClassNotFoundException, SQLException { //예외는 메소드 밖으로 던지기
        Connection c = simpleConnectionMaker.makeNewConnection();
        ....
    }

    public User get(String id) throws ClassNotFoundException, SQLException {
        Connection c = simpleConnectionMaker.makeNewConnection();
        ....
    }
}
  • SimpleConnectionMaker로 분리
  • UserDao가 특정 클래스(SimpleConnectionMaker)에 종속되어 있어 상속을 사용했을 때 코드 수정 없이 DB 커넥션 생성 기능을 변경할 수 없음
  • 문제점 : UserDao가 DB 커넥션에 대한 정보를 너무 많이 갖고 있다
    • 구현체(SimpleConnectionMaker)에 너무 의존적이다
    • 어떤 클래스가 쓰일지, 어떤 메소드를 가지고 있는지 구체적인 방법에 종속됨

인터페이스의 도입

  • 추상적인 느슨한 연결고리
    • 두 개의 클래스가 서로 긴밀하게 연결되지 않도록
    • 추상화 : 어떤 것들의 공통적인 성격을 뽑아내어 이를 따로 분리하는 작업
  • 자바에서는 인터페이스를 통해 추상화를 진행함
  • 인터페이스에서는 어떤 일을 할지만 정해놓고, 어떻게 하는지는 구체 클래스들이 결정

인터페이스 생성

public interface ConnectionMaker {
    public Connection makeConnection() throws ClassNotFoundException, SQLException;
}

인터페이스 구현

public class DConnectionMaker implements ConnectionMaker{

    @Override
    public Connection makeConnection() throws ClassNotFoundException, SQLException {
        //Connection 생성
    }
}

인터페이스 사용하여 DB 커넥션 가져오기

public class UserDao {
    private ConnectionMaker connectionMaker;

    public UserDao() {
        this.connectionMaker = new DConnectionMaker();
    }

    public void add(User user) throws  ClassNotFoundException, SQLException { //예외는 메소드 밖으로 던지기
        Connection c = connectionMaker.makeConnection();
    }

    public User get(String id) throws ClassNotFoundException, SQLException {
        Connection c = connectionMaker.makeConnection();
    }
}
  • 그럼에도 불구하고 UserDao의 생성자에서 DConnectionMaker를 직접 사용하고 있음
  • 커넥션을 변경하려면 UserDao를 변경해야 함
  • 분리되지 않은 또다른 관심사항(DConnectionMaker)이 존재

관계설정 책임의 분리

  • UserDao와 UserDao가 사용할 ConnectionMaker의 구현 클래스 사이의 관계를 설정해주는 역할이 필요
  • 사용되는 쪽이 사용하는 쪽에게 서비스를 제공
  • 서비스 : 사용되는 오브젝트
  • 클라이언트 : 사용하는 오브젝트
  • 클라이언트 오브젝트가 구현 클래스간의 관계를 설정하도록 하면 된다
  • 클래스 사이에 관계가 만들어진다 : 한 클래스가 인터페이스 없이 다른 클래스를 직접 사용한다
    • 코드에 클래스 이름이 나타나는 상황
  • 오브젝트 사이에 관계가 만들어진다 : 런타임 시에 한쪽이 다른 오브젝트의 레퍼런스를 갖고 있다
    • 런타임 시에 서로 사용하게 다이나믹한 관계를 맺어주면 됨
  • 오브젝트 사이 관계 설정
    • 직접 생성자를 호출하여 설정
    • 외부에서 만들어 준 것 가져오기 (메소드 파라미터, 생성자 파라미터 등으로 전달)
    • 다형성 활용 : 클래스의 오브젝트를 인터페이스 타입으로 받아서 사용
  • 클라이언트의 책임
    • 클래스들을 이용해 런타임 오브젝트 관계를 갖는 구조로 만들어주는 것
    • 모델링 시에는 없었지만 다이나믹하게 생성됨
    • 클라이언트는 구현 클래스(세부 전략)를 선택하고 선택한 오브젝트를 생성해 사용해야 할 곳에 던져줌
      • 기존에는 사용해야 할 곳의 생성자에 책임이 있었다
      • 확장성이 떨어지는 상황
    • 대개는 main 메소드가 클라이언트에 해당

책임을 클라이언트에 떠넘기기

public UserDao(ConnectionMaker connectionMaker) {
        this.connectionMaker = connectionMaker;
    }
public class UserDaoTest {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        DConnectionMaker connectionMaker = new DConnectionMaker();
        UserDao dao = new UserDao(connectionMaker);
    }
}
  • 클라이언트인 UserDaoTest가 구현 클래스간의 런타임 오브젝트 의존관계를 설정하는 책임 담당
  • UserDao는 자신의 관심사만 보면 됨

링크 alt

  • 최초 DAO
    • UserDao에서 DB 커넥션 생성, 자원 반환, 사용자 관련 조작 모두 수행
    • DB 관련 코드가 변경되면 UserDao의 모든 메소드를 찾아야 함
  • 관심사의 분리
    • DB 커넥션 가져오는 중복 코드 분리
    • DB 관련 코드가 변경되면 DB 관련 메소드만 수정하면 됨
    • 한 가지 방법으로면 DB 커넥션 가능
  • 상속을 통한 확장
    • 여러 방법으로 DB 커넥션을 가져오고픔
    • UserDao에 DB 커넥션 관련 추상 메소드를 생성하고 서브클래스에서 상속을 받아 사용
    • 자바는 클래스의 다중상속을 허용하지 않기에 한계가 있음
    • 상속으로 이루어진 관계는 밀접함
  • 클래스의 분리
    • 상속을 통한 관계가 아닌 서로 사용하는 관계로 분리
    • 한 클래스가 다른 클래스에 대해 너무 많이 알고 있어서 확장이 어려워짐
  • 인터페이스의 도입
    • 기능에만 관심을 가지고 어떻게 구현되었는지는 관심 가지지 않음
    • 어찌되었든 구체 클래스를 찾아야 함
  • 관계설정 책임의 분리
    • 오브젝트 사이의 관계를 클라이언트가 설정하도록 책임을 떠넘김

카테고리:

업데이트: