Java & Spring/토비의 스프링 3.1

1장 오브젝트와 의존관계 (1.1 초난감 DAO ~ 1.2 DAO의 분리)

Zin0_0 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 메소드라고 함
    • 스프링에서 애용되는 디자인 패턴
  • 팩토리 메소드 패턴
    • 서브클래스에서 구체적인 오브젝트 생성 방법을 결정하게 하는 것
    • 주로 인터페이스 타입으로 오브젝트를 리턴하므로 서브클래스에서 정확히 어떤 클래스의 오브젝트를 만들어 리턴할 지 슈퍼클래스는 알지 못함(관심 X)
    • 서브클래스에서 오브잭트 생성 방법과 클래스를 결정할 수 있도록 미리 정의해둔 메소드를 팩토리 메소드라고 하고, 이를 통해 나머지 로직을 완성
    • 슈퍼클래스의 기본 코드에서 독립시키는 방법
      • 상속을 통해 기능을 확장
    • 스프링에서 애용되는 디자인 패턴
반응형