티스토리 뷰

반응형

P50

  • 스프링이 자바에서 가장 중요하게 가치를 두는 것은 바로 객체지향 프로그래밍 가능한 언어라는 점이다.

1.1 초난감 DAO

1.1.1 User

  • 자바빈 → 아래 두가지 관례를 따라 만들어진 오브젝트
    • 디폴트 생성자 : 자바빈은 파라미터가 없는 디폴트 생성자를 갖고 있어야 한다. 툴이나 프레임워크에서 리플렉션을 이용해 오브젝트를 생성하기 때문에 필요하다.
    • 프로퍼티 : 자바빈이 노출하는 이름을 가진 속성을 프로퍼티라고 한다. 프로퍼티는 set으로 시작하는 수정자 메서드, get으로 시작하는 접근자 메소드를 이용해 수정 또는 조회할 수 있다
# users 테이블 생성 스크립트
create table users(
  id varchar(10) primary key,
  name varchar(20) not null,
  password varchar(10) not null
)

1.1.2 UserDao

1.1.3 main()을 이용한 DAO 테스트 코드 (P58)

  • 초난감 예제코드 작성 745bb35
  • 왜 이코드에 문제가 많다고 하는 것일까? DAO 코드를 개선했을 때의 장점은 무엇일까?
  • 미래에 주는 유익은 무엇인가?
  • 객체지향 설계의 원칙과는 무슨상관이 있을까? ..

1.2 DAO의 분리 (P60)

1.2.1 관심사의 분리

  • 객체지향의 세계에서는 모든 것이 변한다.
  • 그래서 개발자가 객체를 설계할 때 가장 염두에 둬야 할 사항은 바로 미래의 변화를 어떻게 대비할 것인가이다.
  • 객체지향 기술은 흔히 실세계를 최대한 가깝게 모델링해낼 수 있기 때문에 의미가 있다고 여겨진다.
  • 가장 좋은 대첵은 변화의 폭을 최소한으로 줄여주는 것이다.
  • 관심사의 분리라는게 있다. 관심이 같은 것끼리는 하나의 객체 안으로 똔느 친한 객체로 모이게 하고, 다른 것은 가능한 한 따로 떨여저서 서로 영향을 주지 않도록 분리하는 것이라고 생각할 수 있다.

1.2.2 커넥션 만들기의 추출

UserDao의 관심사항

  1. DB연결을 위한 커넥션을 어떻게 가져올까
  2. Statement를 만들고 실행하는 것
  3. 사용한 리로스를 시스템에 돌려주는 것
  • 하나의 관심사가 방만하게 중복되어 있고, 여기저기 흩어져 있어서 다른 관심의 대상과 얽혀 있으면, 변경이 일어날 때 엄청난 고통을 일으키는 원인이 된다.
  • 지저분하게 꼬여 있는 스파게티 코드가 된다는 뜻이다.

중복 코드의 메소드 추출

  • 가장 먼저 할 일은 커넥션을 가져오는 중복된 코드를 분리하는 것이다.
  • 메소드 추출로 커넥션을 가져오는 부분을 추출한다.
private Connection getConnection() throws ClassNotFoundException, SQLException {
    Class.forName("org.h2.Driver");
    return DriverManager
        .getConnection("jdbc:h2:tcp://localhost/~/springbook", "sa", "");
  }

변경사항에 대한 검증: 리팩토링과 테스트

  • 앞에서 만들어뒀던 main() 메소드를 이용한 테스트를 실행해보면 된다.
  • 한가지 단점이 있는데, main 메소드를 여러번 실행하면 두 번째 부터는 무조건 예외가 발생한다는 점이다.
  • 기능이 추가되거나 바뀐 것은 없지만 UserDao는 이전보다 훨씬 깔끔해졌고 미래의 변화에 좀 더 손쉽게 대응할 수 있는 코드가 됐다. → 이런 작업을 리팩토링 이라고 한다.
  • 공통의 기능을 담당하는 메소드로 중복된 코드를 뽑아내는 것을 리팩토링에서는 메소드 추출 기법이라고 부른다

1.2.3 DB 커넥션 만들기의 독립

  • N사와 D사에 소스코드를 제공해주지 않고도 고객 스스로 원하는 DB커넥션 생성 방식을 적용해가면서 UserDao를 사용하게 할 수 있을까?

상속을 통한 확장

  • getConnection() 을 추상 메소드로 만들어 놓는다.
  • 기능의 일부를 추상 메소드나 오버라이딩이 가능한 protected 메소드 등으로 만든 뒤 서브 클래스에서 이런 메소드를 필요에 맞게 구현해서 사용하도록 하는 방법을 디자인 패턴에서 템플릿 메소드 패턴 이라고한다

  • 그리고 UserDao의 서브클래스의 getConnection() 메소드는 어떤 Connection 클래스의 오브젝트를 어떻게 생성할 것인지를 결정하는 방벙이라고 볼 수 있다.

  • 이렇게 서브클래스에서 구체적인 오브젝트 생성방법을 결정하게 하는 것을 팩토리 메소드 패턴 이라고 부르기도 한다.

  • getConnection() 메소드에서 생성하는 Connection 오브젝트의 구현 클래스는 제각각이겠지만 UserDao는 Connection 인터페이스타입의 오브젝트라는 것 외에는 관심을 두지 않는다. → P68

  • 그저 Connection 인터페이스에 정의된 메소드를 사용할 뿐이다.


디자인 패턴

  • 소프트웨어 설계 시 특정 상황에서 자주 만나는 문제를 해결하기 위해 사용할 수 있는 재사용 가능한 솔루션을 말한다.

템플릿 메소드 패턴

  • 상속을 통해 슈퍼 클래스의 기능을 확장할 때 사용하는 가장 대표적인 방법이다.
  • 변하지 않는 기능은 슈퍼클래스에 만들어 두고 자주 변경되며 확장할 기능을 서브클래스에서 만들도록한다.

팩토리 메소드 패턴

  • 슈퍼클래스 코드에서는 서브클래스에서 구현할 메소드를 호출해서 필요한 타입의 오브젝트를 가져와 사용한다.
  • 이 메소드는 주로 인터페이스 타임으로 오브젝트를 리턴
  • 서브클래스에서 정확히 어떤 클래스의 오브젝트를 만들어 리턴할지는 슈퍼클래스에서는 알지 못한다.
  • 사실 관심도 없다.
  • 하지만 이 방법은 상속을 사용했다는 단점이 있다.
  • 상속은 많은 한계점이 있다.
  • 만약 이미 UserDao가 다른 목적을 위해 상속을 사용하고 있다면 어쩔 것인가?
  • 그리고 상속을 통한 상하위 클래스의 관계는 생각보다 밀접하다
  • 상속관계는 두 가지 다른 관심사에 대해 긴밀한 결함을 허용한다.
    • 서브클래스는 슈퍼클래스의 기능을 직접 사용할 수 있다.
    • 슈퍼클래스 내부의 변경이 있을 때 모든 서브클래스를 함께 수정하건 다시 개발해야 할 수도 있다.
    • 예를들면 추상메소드를 하나더 추가한다면? 서브클래스를 다 수정해야한다.

1.3 DAO의 확장

  • 여러가지 단점이 많은(위에서 설명한), 상속이라는 방법을 사용했다는 사실이 불편하게 느껴진다

1.3.1 클래스의 분리

  • 이번에는 상속관계도 아닌 완전히 독립적인 클래스로 만들어 보겠다.
  • 단지 내부 설계를 변경해서 좀 더 나은 코드로 개선했을 뿐이다.
  • 상속을 통해 DB커넥션 기능을 확장해서 사용하게 했던 게 불가능해졌다.
  • SimpleConnectionMaker라는 특정 클래스에 종속되어 있기 때문에 상속을 사용했을 때 처럼 UserDao코드의 수정없이 DB커넥션 생성 기능을 변경할 방법이 없다.
  • 클래스를 분리한 경우에도 상속을 이용했을 때와 마찬가지로 자유로운 확장이 가능하게 하려면 두가지 문제를 해결해야 한다
  1. SimpleConnectionMaker의 메소드
  2. DB커넥션을 제공하는 클래스가 어떤 것인지를 UserDao가 구체적으로 알고 있어야하는 점

1.3.2 인터페이스 도입

  • 추상화란
    • 어떤 것들의 공통적인 성격을 뽑아내어 이를 따로 분리해내는 작업이다.
  • 인터페이스는 자신을 구현한 클래스에 대한 구체적인 정보는 모두 감춰버린다.
  • 인터페이스를 통해 접근하게 하면 실제 구현클래스를 바꿔도 신경 쓸 일이 없다.
  • 단지 인터페이스를 통해 원하는 기능을 사용하기만 하면된다.
  • UserDao의 다른 모든 곳에서는 인터페이스를 이용하게 만들어서 DB커넥션을 제공하는 클래스에 대한 구체적인 정보는 모두 제거가 가능했지만, 초기에 한 번 어떤 클래스의 오브젝트를 사용할지를 결정하는 생성자의 코드는 제거되지 않고 남아있다.

1.3.3 관계설정 책임의 분리

  • UserDao에는 어떤 ConnectionMaker 구현 클래스를 사용할지를 결정하는 new NConnection()라는 코드가 있다.
  • 이 코드는 기존 UserDao의 관심사인 JDBC API와 User오브젝트를 이용해 DB에 정보를 넣고 빼는 것도 아니고, ConnectionMaker인터페이스로 대표되는 DB 커넥션을 어떻게 가져올 것인가라는 관심사도 아니다.
  • UserDao의 클라이언트 오브젝트가 바로 제 3의 관심사항인 UserDao와 ConnectionMaker 구현 클래스의 관계를 결정해주는 기능을 분리해서 두기에 적절한 곳이다.
  • 직접 생성자를 호출해서 오브젝트를 만드는 방법도 있지만 외부에서 만들어준 것을 가져오는 방법도있다
  • 현재는 UserDao 클래스의 main()메소드가 UserDao 클라이언트라고 볼 수 있다.
  • b00f9a2

1.3.4 원칙과 패턴

개방 폐쇄 원칙

높은 응집도와 낮은 결합도

  • 높은 응집도
    • 응집도가 높다는 것은 변화가 일어날 때 해당 모듈에서 변하는 부분이 크다는 것으로 설명할 수도 있다.
    • 즉 변경이 일어날 때 모듈의 많은 부분이 함께 바뀌다면 응집도가 높다고 말할 수 있다.
  • 낮은 결합도
    • 책임과 관심사가 다른 오브젝트 또는 모듈과는 낮은 결합도, 즉 느슨하게 연결된 형태를 유지하는 것이 바람직하다.
    • 결합도가 낮아지면 변화에 대응하는 속도가 높아지고, 구성이 깔끔해진다. 또한 확장하기에도 매우 편리하다.
  • 하나의 변경이 발생할 때 마치 파문이 이는 것처럼 여타 모듈과 객체로 변경에 대한 요구가 전파되지 않는 상태를 말한다.

전략 패턴

  • 자신의 기능 맥락에서, 필요에 따라 변경이 필요한 알고리즘을 인터페이스를 통해 통째로 외부로 분리시키고, 이를 구현한 구체적인 알고리즘 클래스를 필요에 따라 바꿔서 사용할 수 있게 하는 디자인 패턴이다.

1.4 제어의 역전(IoC)

  • 제어의 역전 Inversion of Control

1.4.1 오브젝트 팩토리

  • UserDaoTest는 UserDao의 기능이 잘 작동하는지를 테스트하려고 만들었는데 떠맡고있다.

팩토리

  • 분리시킬 기능을 담당할 클래스를 만들어보자
  • 이 클래스의 역할은 객체의 생성 방법을 결정하고 그렇게 만들어진 오브젝트를 돌려주는 것인데, 이런 일을 한느 오브젝트를 팩토리라고 부른다.

설계도로서의 팩토리

  • DaoFactory를 분리했을 때 얻을 수 있는 장점은 매우 다양하다
  • 그중에서도 애플리케이션의 컴포넌트 역할을 하는 오브젝트와 애플리케이션의 구조를 결정하는 오브젝트를 분리했다는 데 가장 의미가 있다.

1.4.2 오브젝트 팩토리의 활용

1.4.3 제어권의 이전을 통한 제어관계 역전

  • P93
  • 프레임워크가 어떤 것인지 이해하려면 라이브러리와 프레임워크가 어떻게 다른지 알아야 한다.
  • 라이브러리를 사용하는 애플리케이션 코드는 애플리케이션 흐름을 직접 제어한다.
  • 단지 동작하는 중에 필요한 기능이 있을 때 능동적으로 라이브러리를 사용할 뿐이다.
  • 반면에 프레임워크는 거꾸로 애플리케이션 코드가 프레임워크에 의해 사용된다.
  • 프레임워크가 흐름을 주도하는 중에 개발자가 만든 애플리케이션 코드를 사용하도록 만드는 방식이다.
  • 프레임워크에는 분명한 제어의 역전 개념이 적용되어 있어야 한다.

1.5 스프링의 IoC

1.5.1 오브젝트 팩토리를 이용한 스프링 IoC

애플리케이션 컨텍스트와 설정정보

  • 스프링에서는 스프링이 제어권을 가지고 직접 만들고 관계를 부여한느 오브젝트를 이라고 부른다.
  • 스프링에서는 빈의 생성과 관계설정 같은 제어를 담당하는 IoC오브젝트를 빈 팩토리 라고 부른다.
  • 빈 팩토리 == 애플리케이션 컨텍스트

DaoFactory를 사용하는 애플리케이션 컨텍스트

  • DaoFactory를 스프링의 빈을 이용하도록 수정
  • getBean은 기본적으로 Object타입으로 리턴하게 되어 있어서 매번 리턴되는 오브젝트에 다시 캐스팅을 해줘야 하는 부담이 있었는데 자바 5이상의 제네릭 메소드 방식을 이용해 두번째 파라미터에 리턴타입을 주면, 지저분한 캐스팅 코드를 사용하지 않아도 된다.

1.5.2 애플리케이션 컨텍스트의 동작방식

DaoFactory를 오브젝트 팩토리로 직접 사용했을때와 비교했을 때 장점

  1. 클라이언트는 구체적인 팩토리 클래스를 알 필요가 없다.
  2. 애플리케이션 컨텍스트는 종합 IoC 서비스를 제공해준다
  3. 애플리케이션 컨텍스트는 빈을 검색하는 다양한 방법을 제공한다.

1.5.3 스프링 IoC의 용어정리

    • 스프링이 IoC방식으로 관리하는 오브젝트
  • 빈 팩토리
    • 스프링의 IoC를 담당하는 핵심 컨테이너를 가리킨다
  • 애플리케이션 컨텍스트
    • 빈 팩토리를 확장한 IoC 컨테이너다.
    • 스프링이 제공하는 각종 부가 서비스를 추가로 제공한다.
  • 설정정보/설정 메타정보
    • configuration
    • 애플리케이션 컨텍스트 또는 빈 팩토리가 IoC를 적용하기 위해 사용하는 메타정보
  • 컨테이너 또는 IoC컨테이너
    • IoC방식으로 빈을 관리한다는 의미에서 애플리케이션 컨텍스트나 빈 팩토리를 컨테이너 또는 IoC 컨테이너라고도 한다.

1.6 싱글톤 레지스트리와 오브젝트 스코프

오브젝트의 동일성과 동등성

  • 동일성은 ==
  • 동등성은 equals()
  • 자바 클래스를 만들때 equals() 를 따로 구현하지 않았다면 최상위 클래스인 오브젝트 클래스에 구현되어있는 equals 메소드가 사용된다.

1.6.1 싱글톤 레지스트리로서의 애플리케이션 컨텍스트

서버 애플리케이션과 싱글톤

  • 왜 스프링은 싱글톤으로 빈을 만드는 것일까?
    • 스프링이 주로 적용되는 대상이 자바 엔터프라이즈 기술을 사용하는 서버환경이기 때문이다.
  • 서블릿은 대부분 멀티 스레드 환경에서 싱글톤으로 동작한다.
  • 서블릿 클래스당 하나의 오브젝트만 만들어두고, 사용자의 요청을 담당하는 여러 스레드에서 하나의 오브젝트를 공유해 동시에 사용한다.

싱글톤 패턴의 한계

싱글톤 레지스트리

  • 스프링은 서버환경에서 싱글톤이 만들어져서 서비스 오브젝트방식으로 사용되는 것은 적극 지지한다.
  • 장점
    • 스태틱 메소드와 private 생성자를 사용해야 하는 비정상적인 클래스가 아니라 평범한 자바 클래스를 싱글톤으로 활용하게 해준다는 점이다.
  • 싱글톤으로 사용돼야 하는 환경이 아니라면 간단히 오브젝트를 생성해서 사용할 수 있다.
  • 따라서 테스트 환경에서 자유롭게 오브젝트를 만들 수 있고, 테스트를 위한 목 오브젝트로 대체하는것도 간단하다.
  • 스프링은 IoC컨테이너일 뿐만 아니라, 고전적인 싱글톤 패턴을 대신해서 싱글톤을 만들고 관리해주는 싱글톤 레지스트리라는 점을 기억해두자

1.6.2 싱글톤과 오브젝트의 상태

  • 메소드 안에서 생성되는 로컬 변수는 매번 새로운 값을 저장할 독립적인 공간이 만들어지기 때문에 싱글톤이라고 해도 여러스레드가 변수의 값을 덮어쓸 일이 없다.
  • 자신이 사용하는 다른 싱글톤 빈을 저장하려는 용도라면 인스턴스 변수를 사용해도 좋다.
  • 동일하게 읽기전용의 속성을 가진 정보라면 싱글톤에서 인스턴스 변수로 사용해도 좋다.
  • 물론 단순한 읽기전용 값이라면 static final이나 final로 선언하는 편이 나을 것이다.

1.6.3 스프링의 스코프

  • 스프링 빈의 기본 스코프는 싱글톤이다.
  • prototype 은 싱글톤과 달리 컨테이너에 빈을 요청할 때마다 매번 새로운 오브젝트를 만들어준다.

1.7 의존관계 주입 (DI)

  • 스프링 IoC 기능의 대표적인 동작원리는 주로 의존관계 주입이라고 불린다.
  • DI는 오브젝트 레퍼런스를 외부로부터 제공받고 이를 통해 여타 오브젝트와 다이내믹하게 의존관계가 만들어지는 것이 핵심이다.

1.7.2 런타임 의존관계 설정

의존관계

  • 의존관계에는 방향성이 있다.
  • A가 B에 의존하고 있지만, B는 A에 의존하지 않는다.
    • 의존하지 않는다는 말은 B는 A의 변화에 영향을 받지 않는다.

UserDao의 의존관계

  • 인터페이스에 대해서만 의존관계를 만들어두면 인터페이스 구현 클래스와의 관계는 느슨해지면서 변화에 영향을 덜 받는 상태가 된다.
  • 결합도가 낮다고 설명할 수 있다.
  • 프로그램이 시작되고 UserDao 오브젝트가 만들어지고 나서 런타임 시에 의존관계를 맺는 대상, 즉 실제 사용대상인 오브젝트를 의존 오브젝트 라고 말한다

UserDao의 의존관계 주입

  • P116

1.7.3 의존관계 검색과 주입

  • 의존관계를 맺는 방법이 외부로부터 주입이 아니라 스스로 검색을 이용하기 때문에 의존관계 검색 이라고 불리는 것도 있다.
  • 자신이 필요로 하는 의존 오브젝트를 능동적으로 찾는다.
  • 스프링의 IoC컨테이너인 애플리케이션 컨텍스트는 getBean()이라는 메소드를 제공한다.
  • 이 메소드가 의존관계 검색에 사용되는 것이다

1.7.4 의존관계 주입의 응용

기능 구현의 교환

  • 로컬 Connction에서 운영 환경 Connection으로 교체해야하는 예

부가기능 추가

1.7.5 메소드를 이용한 의존관계 주입

  • 수정자 메소드를 이용한 주입
  • 일반 메소드를 이용한 주입

1.8.3 DataSource 인터페이스로의 변환

value값의 자동 변환

1.9 정리

  • 스프링을 사용한다고 좋은 객체지향 설계와 깔끔하고 유연한 코드가 저절로 만들어 질까?
  • 그건 절대 아니다
  • 그 부분은 객체지향 설계와 프로그래밍에 대한 학습과 훈련, 경험이 필요한 부분이며 각자가 공부해야 할 책임이 있는 과제다.
  • 다만 스프링은 그런 좋은 설계와 코드를 적용하고자 할 때 좋은 동반자가 돼줄 것이다.

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함