ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 1장 오브젝트와 의존관계 (1.1 초난감 DAO ~ 1.2 DAO의 분리)
    Java & Spring/토비의 스프링 3.1 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)
      • 서브클래스에서 오브잭트 생성 방법과 클래스를 결정할 수 있도록 미리 정의해둔 메소드를 팩토리 메소드라고 하고, 이를 통해 나머지 로직을 완성
      • 슈퍼클래스의 기본 코드에서 독립시키는 방법
        • 상속을 통해 기능을 확장
      • 스프링에서 애용되는 디자인 패턴
    반응형

    댓글

Designed by Tistory.