🔮 오브젝트와 의존관계

😖난감한 DAO

데이터 베이스를 이용해 데이터를 조회하거나 조작하는 기능을 전담하는 오브젝트이다.
자바 빈 객체를 DB라고 봤을때 그 객체에 관한 CRUD같은 DB관련 기능들을 정의해 사용하는 오브젝트이다.

✔️ JavaBean : 디폴트 생성자를 가지고있고, getter/setter 프로퍼티를 소유한 오브젝트

🔌 JDBC

  1. 드라이버 로딩 (JDBC Load)
    • Class.forName("드라이버 Path")
      • Class 클래스가 클래스의 정보(필드, 메서드 클래스의 종류)를 담는 메타 클래스이고
        JVM은 해당 클래스의 정보를 로드한다.
  1. DB 연결 Connection
    • DriverManager.getConnection(url, ID, PWD)
      • Connection 객체를 생성한후
      • DriverManager에서 시스템 프로퍼티 "jdbc.drivers"에 참조된 드라이버 클래스를 로드한다.
      • 이후 Connection 객체에 할당
  1. 쿼리 생성 및 질의

     PreparedStatement psmt = null;
     psmt = conn.prepareStatement("SQL문");
    
     Statement stmt = null;
     stmt = conn.createStatement("SQL문");

    ✔️ PreparedStatement는 쿼리에 ?로 매개변수를 받아 실행 가능

  1. 쿼리 실행

    • psmt.executeUpdate()
      • INSERT UPDATE DELETE 같은 값을 받아오지 않는 쿼리문은 psmt.executeUpdate()로 실행
    • psmt.executeQuery()
      • SELECT 처럼 결과 테이블이 필요한 쿼리문은 쿼리 실행 이전에 ResultSet객체를 생성한후 psmt.executeQuery()를 할당한다.
  2. ResultSet 처리

     while(rs.next()) {
         int i=1;
         int id = rs.getInt(i++);
         String name = rs.getString(i++);
         String addr = rs.getString(i++);
      }
  1. Close()

     if (rs!=null) {
        try {
           rs.close();
        } catch (SQLException e) {
        }
     }
    
     if(stmt!=null) {
        try {
           stmt.close();
        } catch (SQLException e) {
        }
     }
    
     if(conn!=null) {
        try {
           conn.close();
        } catch (SQLException e) {
        }
     }

    ✔️ Open한 객체들의 역순으로 close 시킨다.

💔 DAO의 분리

위의 6단계를 거친 DAO객체의 메서드 처리 과정은 객체지향의 특징과는 어긋나있는 점이 많다.
개발에게는 객체지향의 확장성과 유연함 을 고려한 설계가 요구되며
각각의 객체들에 대한 관심사의 구분 이 적절하게 나누어 질 수 있도록 설계해야 한다.

  • Connection 생성 과정의 중복
    👉 독립적인 메소드를 만들어 분리
    : 공통의 기능을 담당하는 메소드로 중복을 제거하는 것을 리팩토링에서는 메소드 추출이라 한다.

공통기능을 독립시키기

위에서 리팩토링한 DAO를 사용할 경우 Connection의 중복은 제거되었지만 객체지향의 유연한 특징은 발휘되지 않았다.
DAO를 다른 환경에서 이용할때의 부분적인 수정이 이루어 지도록 하는 방법도 존재한다.

상속을 통한 확장

구현해놓은 메소드를 추상화 시키고 DAO 클래스를 상속받는 서브클래스를 만든다.
즉, 클래스의 계층구조를 나누어 분리시키는 것이다.

✔️ 위와같이 클래스를 추상화 시킨후 각각의 서브클래스들로부터 부분적인 코드를 원하는대로
각각 구현하는 방법을 '템플릿 메소드 패턴' 이라고 한다.

❗ 상속을 이용한 확장은 간단하면서도 효과적이지만 다른 객체를 상속받을 수 없다는 점
❗ 부모 클래스의 변경이 이루어 질 경우 적합성이 보장되지 않는다는 단점이 존재한다.

DAO의 확장

위에서 언급한 데이터 접근 로직(분리)과 DB연결 방법을 고려하는것(상속)은 다른 변화의 성격을 띄고있다.
이 말은 각각의 방법이 어느 한 관심사에 집중된 상태로 그 관심사(코드의 중복, 객체지향의 유연함)를 해결하기 위한 방법이라는 말이다.

즉, DAO에 관한 다른 관점이 생긴다면 그 부분으로 관심사가 바뀔수 있고
앞서 언급한 각각의 방법 외에 다른 방법으로는 완전한 독립적인 클래스로 만드는것이 있다.

새로운 객체를 생성하는 경우

새로운 객체를 생성하여 사용하는것은 다시 유연성 확보에 관한 문제점을 야기한다.

DAO클래스가 새로운 객체에 종속되어 상속을 받을때와는 다르게 DAO에 수정이 가해질 수 있기 때문이다.

인터페이스의 도입은 이러한 문제점을 해결할 수 있는 해결책으로 제시된다.

인터페이스는 상속과는 비슷하지만 다르다 상위 개념을 하위에서 받아 사용하는것이 상속이라면

하위 클래스의 특정한 메소드가 반드시 존재하도록 강제하는것이 인터페이스이다

이처럼 인터페이스를 이용한 추상화 방법은 클래스와 함께 인터페이스도 전달하여

개발자에게 전달된 인터페이스의 구현을 행하도록 하는것이다.

즉, DAO의 입장에서 DB연결 방법에 관한 코드를 인터페이스화 시킨다는 의미는

같은 인터페이스를 사용하는 객체들 사이의 규약이 정해져 어떤 상황이든 DB커넥션을 가져올 수 있는것이다.

예제 1-10 에서는 add()`` get()의 메서드 모두 makeConnection() 인터페이스에 정의되어있는 메서드를

사용하는데, 이 코드의 관한 서술과 동작은 인터페이스를 사용하는 다른 객체에서 이루어진다는 것이다.

관계설정 책임의 분리

이해 잘 안되서 다시봐야..

📌 원칙과 패턴

⭐ SOLID

자기 자신 클래스 안에 응집도는 내부적으로 높이고, 타 클래스들 간 결합도는 낮추는 High Cohesion - Loose Coupling 원칙을 객체 지향의 관점에서 도입한 것이다.

  • 높은 응집도
    • DAO의 경우 Data Access Object라는 목적에 맞게 데이터를 처리하는 기능만을 가지고 있는 모습
  • 낮은 결합도
    • 필요한 관계에서만 interface를 통해 최소한의 연결을 유지하는 모습

✔️ 다시말해 응집도가 높은 각 모듈을 재사용함으로써, 수정을 최소화하여 유지보수를 용이하기 위함이다.

SRP (Single Responsibility Principle) 단일 책임 원칙

하나의 클래스안에 많은 속성을 넣지말고, 필요한 클래스의 역할과 목적에 맞는 속성과 메서드들을 추려 하나의 클래스들로 각각 만들어야 한다.

OCP (Open Closed Principle) 개방 폐쇄 원칙

개발 방향을 상위 클래스 혹은 인터페이스를 중간에 두어 직접적인 연동을 피하게 설계한다.

LSP (Liskov Substitution Principle) 리스코프 치환 원칙

상속의 개념을 위아래 계층으로 나누는것이 아닌 분류하는것으로 생각하는 관점으로 상속을 확장의 개념으로 설계하는것

Father harry = new Son();
- 해리라는 이름의 아들이 아버지의 행동을한다.

Animal mickey = new Rat();
- 미키라는 이름의 쥐가 동물의 행동을 한다.

✔️ 클래스의타입 이름 = new 하위클래스();로 기억하자.

ISP (Interface Segregation Principle) 인터페이스 분리 원칙

SRP와 같은 원인에 대한 다른 해결책을 제시한다.
이미 만들어진 여러개의 속성과 메서드를 인터페이스 를 통해 판단하여 상황에 맞게 사용한다는 방식

DIP (Dependency Inversion Principle) 의존 역전 원칙

상위 클래스가 하위클래스를 의존하는 상황을 인터페이스나 상위클래스를 하나 더 두어 의존하고 있는 방향을 역전 시키는것

✔️ 의미적으로 OCP 개방 폐쇄 원칙 과 유사하다.

💡 전략 패턴

필요에 따라 변경이 필요한 알고리즘을 인터페이스를 통해 분리시키고, 구현한 로직에 따라 바꿔서
사용할 수 있게한 디자인 패턴이다.

앞서 예로든 ConnectionMaker에서 연결방식을 정의하고 이를 구현하고 있는 클래스의 구조에서
인터페이스를 통한 각각의 Connection이 전략을 바꿔가며 이용되는것을 말한다.

🎯 제어의 역전 (IoC)

객체의 생성과 사용하는 행위를 담당하는 주체가 Container로 넘어가는것을 말한다.

  • 팩토리
    • 객체의 생성 방법을 결정 하고 그렇게 만들어진 오브젝트를 돌려주는 일 을 하는 객체

다시말해 제어의 역전은 오브젝트가 자신이 사용할 오브젝트를 선택하지 않으며 생성하지도 않고

생성과 반환을 자신이 아닌 다른대상 (팩토리) 에 위임하는 것으로 제어권한을 갖는 하나의 특별한

오브젝트에 의해 결정되고 만들어 지는것이다.

✔️ 서블릿에서의 오브텍트 생성, 메서드 호출이 컨테이너 안에서 이루어 지는것과 같은 개념이다.
✔️ 관심의 분리와 책임을 나누는 유연함을 위한 확장 구조를 만드는 과정 자체가 모두 IoC를 위한 작업이었던 셈이다.