스프링의 정수는 엔터프라이즈 서비스 기능을 POJO에 제공하는 것

Professional SPring FrameworkRod Johnson 외 4명
  • 스프링의 주요 기술인 Ioc/DI, AOP와 PSA(Portable Service Abstraction)는 애플리케이션을 POJO로 개발할 수 있게 해주는 가능 기술이라고 불린다

POJO란

  • Plain Old Java Object의 약자
  • 직역하면 평범한 오래된 자바 객체다

POJO의 조건

  1. 특정 규약에 종속되지 않는다.
    • 객체지향 설계의 자유로운 적용이 가능한 오브젝트여야만 POJO라고 불릴 수 있다.
  2. 특정 환경에 종속되지 않는다
    • 환경에 독립적이어야 한다.
    • 특히 비즈니스 로직을 담고 있는 POJO 클래스는 웹이라는 환경정보나 웹 기술을 담고 있는 클래스나 인터페이스를 사용해서는 안된다.
      • 설령 나중에 웹 컨트롤러와 연결돼서 사용될 것이 뻔하도 할지라도
    • 비즈니스 로직을 담은 코드에 HttpServletRequest나 HttpSession, 캐시와 관련된 API가 등장하거나 웹 프레임워ㅏ크의 클래스를 직접 이용하는 부분이 있다면 그것은 진정한 POJO라고 볼 수 없다.

진정한 POJO란 객체지향적인 원리에 충실하면서, 환경과 기술에 종속되지 않고 필요에 따라 재활용될 수 있는 방식으로 설계된 오브젝트를 말한다

POJO의 장점

  1. 특정한 기술과 환겨엥 종속디지 않는 오브젝트는 그만큼 깔끔한 코드가 될 수 있다.
  2. POJO로 개발된 코드는 자동화된 테스트에 매우 유리하다.
  3. 객체지향적인 설계를 자유롭게 적용할 수 있다.

POJO 프레임워크

  • POJO 프로그래밍이 가능하도록 기술적인 기반을 제공하는 프레임워크
  • 스프링 프레임워크와 하이버네이트 등

POJO를 가능하게 하는 스프링의 기술

  1. Ioc/DI
  2. AOP
  3. PSA

제어의 역전(Ioc) / 의존관계 주입(DI)

  • 왜 두개의 오브젝트를 분리해서 만들고, 인터페이스를 두고 느슨하게 연결한 뒤, 실제 사용할 대상은 DI를 통해 외부에서 지정하는 걸까?
  • 이렇게 DI 방식으로 하는 것이 직접 사용할 오브젝트를 new 키워드로 생성해서 사용하는 강한 결합을 쓰는 방법보다 나은 점은 무엇일까?

= 유연한 확장이 가능하게 하기 위해

  • A->B라는 의존관계가 있을 떄 확장은 B가 자유롭게 변경될 수 있음을 의미
  • 이는 B가 변경되어도 A는 아무 영향이 없고 그대로 유지 가능
    B 관점에선 유연한 확장이고, A 관점에서는 변경 없이 재사용이 가능함
  • 개방 폐쇄 원칙(OCP)라는 객체지향 설계 원칙으로 설명할 수 있음

애스펙트 지향 프로그래밍(AOP)

  • 객체지향 기술만으로는 애플리케이션의 요구조건과 기술적인 난해함을 모두 해결하는데 한계가 있음
  • 이를 도와주는 보조적인 프로그래밍 기술이 AOP
  • 스프링의 AOP는 스프링이 POJO 프로그래밍을 지원하려는 그 핵심 목적을 위해 중요한 역할을 하고 있음

포터블 서비스 추상화(PSA)

  • POJO로 개발된 코드는 특정 환경이나 구현 방식에 종속적이지 않아야 함
  • 환경과 세부 기술의 변화에 관계없이 일관된 방식으로 기술에 접근 할 수 있게 해주는게 PSA
  • 단순히 구체적인 기술에 종속되지 않게 하기 위해서 말고 테스트가 어렵게 만들어진 API나 설정을 통해 주요 기느을 외부에서 제어하게 만들고 싶을 때도 이용할 수 있음

댓글 공유

스프링의 정의

자바 엔터프라이즈 개발을 편하게 해주는 오플ㄴ소스 경량급 애플리케이션 프레임워크

이일민토비의 스프링

애플리케이션 프레임워크

  • 특정 계층이나, 기술, 업무 분야에 국한되지 않고 애플케이션의 전 영역을 포괄하는 범용적인 프레임워크
  • 애플리케이션 개발의 전 과정을 빠르고 편리하며 효율적으로 진행하는데 목표를 두는 프레임워크
  • 단지 여러 계층의 다향한 기술을 한데 모아뒀기 때문에 그렇게 불리는 게 아님

스프링의 일차적인 존재 목적은 핵심 기술에 담긴 프로그래밍 모델을 일관되게 적용해서 엔터프라이즈 애플리케이션 전 계층과 전 여영ㄱ에 전략과 기능을 제공해줌으로써 애플리케이션을 편리하게 개발하게 해주는 애플리케이션 프레임워크로 사용되는 것

경량급

  • 자체가 가렵다거나 작은 규모의 코드로 이뤄졌다는 뜻이 아님
  • 불필요하게 무겁지 않다는 의미
  • EJB에 비해 단순한 개발툴과 기본적인 개발환경으로도 엔터프라이즈 개발에서 필요로 하는 주요한 기능을 갖춘 애프리케이션을 개발하기 충분

자바 엔터프라이즈 개발을 편하게

  • 개발자가 복잡하고 실수하기 쉬운 로우레벨 기술에 많은 신경을 쓰지 않게함
  • 애플리케이션의 핵심인 사용자의 요구사항, 즉 비즈니스 로직을 빠르고 효과적으로 구현하는 것
  • 스프링이 제공하는 기술이 아니라 자신이 작성하는 애플리케이션의 로직에 더 많은 관심과 시간을 투자하게 함
  • 초기에 기본 설정과 적용 기술만 선택하고 준비해두면 이후에 개발자가 신경 쓸 일이 없음

결국 스프링의 목적은 스프링을 할용해서 엔터프라이즈 애플리케이션 개발을 편하게 하는 것
그렇다면 스프링은 어떻게 복잡한 엔터프라이즈 개발을 편하게 해주는가?


복잡함의 근본적인 이유

  1. 기술적인 제약조건과 요구사항이 늘어남
  2. 애플리케이션이 구현해야 할 핵심기능인 비즈니스 로직의 복잡함이 증가함
  • 자바 엔터프라이즈 시스템 개발이 어려운 가증 큰 이유는 근본적인 비즈니스 로직과 엔터프라이즈 기술이라는 두 가지 복잡함이 한데 얽혀 있기 때문

해결책

  • 기술의 적용 사실이 코드에 직접 반영되지 않는 비침투적 기술 사용

  • 어딘가에는 기술의 적요에 따라 필요한 작업을 해줘야하겠지만, 애플리케이션 코드 여기저기에 불쑥 등장하거나, 코드의 설꼐와 구현 방식을 제한하지 않는다는 게 비침투적인 기술의 특징

  • 반대로 침투적인 기술은 어떤 기술을 적용했을 떄 그 기술과 관련된 코드나 규약 등이 코드에 등장하는 경우

  • 즉 스프링의 기본적인 전량근 비즈니스 로직을 담은 애플리케이션 코드와 엔터프라이즈 기술을 처리하는 코드를 분리시키는 것

기술적 복잡함을 상대하는 전략

서비스 추상화

  • 일관성 없는 기술과 서버환경의 변화에 대한 스프링의 공략 방법은 서비스 추상화
  • 추상화를 통해 로우레벨의 기술 구현 부분과 기술을 사용하는 인터페이스를 분리하고, 환경과 세부기술에 독립적인 접근 인터페이스를 제공하는 것이 가장 좋은 해결책

AOP

  • 비즈니스 로직 전후로 경계가 설정돼야하는 트랜잭션
  • 비즈니스 로직에 대한 보안 적용
  • 계층 사이에 주고받는 데이터와 예외의 일괄 변환이나 로징이나 감사 기능 등
  • 이런 기술과 비즈니스 로직의 혼재로 발생하는 복잡함을 해결하기 위한 스프링의 접근 방법이 AOP

비즈니스와 애플리케이션 로직의 복잡함을 상대하는 전략

객체지향과 DI

  • 기술적인 복잡함을 효과적으로 다루게 해주는 기법은 모두 DI를 바탕으로 함
  • 서비스 추상화, 템플릿/콜백, AOP 등
  • 그리고 DI는 객체지향 프로그래밍 기법일 뿐
  • DI를 적용해서 오브젝트를 분리하고, 인터페이스를 동비하고, DI로 관계를 연결
  • 결국 DI는 좋은 오브젝트 설계의 결과물이기도 하지만, 반대로 DI를 적용하다보면 객체지향 설계의 원칙을 잘 따르고 그 장점을 살린 설계가 나올 수 있음

결국 스프링의 기술과 전략은 객체지향이라는 자바 언어가 가진 강력한 도구를 극대화해서 사용할 수 있도록 돕는 것 이고 스프링은 단지 거들 뿐이다.

댓글 공유

AOP란

  • AOP는 Ioc, DI, 서비스 추상화와 더불어 스프링의 3대 기반 기술
  • 선언적 트랜잭션 기능이 대표적

트랜잭션 코드의 분리

  • 비즈니스 로직 전 후에 로직과 전혀 상관없는 트랜잭션 경계를 설정해야 하기 때문에 필연적으로 코드가 지저분해짐

메서드 분리를 이용해 분리

  • 비즈니스 로직을 담당하는 코드만 따로 메서드로 추출
  • 하지만 여전히 비즈니스 로직이 아닌 보일 필요가 없는 트랜잭션 코드가 남아있음
  • 그렇다면 클래스에서 빼서 아예 눈에 안띄게 해버리자

DI를 이용한 클래스의 분리

  • DI의 기본 아이디어는 실제 사용할 오브젝트의 클래스 정체는 감춘 채 인터페이스를 통해 간접으로 접근하는 것

  • 그 덕분에 구현 클래스는 얼마든지 외부에서 변경 가능

  • UserService 인터페이스를 상속 받는 클래스를 2 가지로 나눔

    1. ServiceImpl(비즈니스 담당)
    2. ServiceTx(트랜잭션 담당)
  • Impl에선 비즈니스 로직을 담당하는 메서드만 남겨두고 Tx에선 userService를 구현한 다른 오브젝트를 주입 받고 트랜잭션 안에서 동작할 수 있도록 메서드 안에서 트랜잭션 경계를 설정

1
2
3
4
5
6
7
public void upgardeLevels() {
트랜잭션 스타트();

주입받은 userService를 구현한 오브젝트(Impl).upgrardeLevels();

commit() or rollback();
}

DI를 이용한 트랜잭션 경계설정 코드 분리의 장점

  1. 비즈니스 로직만 담긴 Impl 클래스에선 코드을 작성 시 트랜잭션 같은 비즈니스 로직과 관계 없는 부분에 대해 전혀 신경 쓰지 않아도 됌
  2. 테스트가 쉬워짐

다시 돌아와 AOP: 애스펙트(aspect) 지향 프로그래밍

  • 부가기능 모듈화 작업
  • 핵심기능에 부가되어 의미를 갖는 특별한 모듈
  • 에스펙트는 부가될 기능을 정의한 코드인 어드바이스, 어드바이스를 어디에 적용할지를 결정하는 __포인터컷__을 함께 갖고 있음
  • 위에서 트랜잭션 코드는 비즈니스 로직에 상관없는 기능인데 핵심기능에 침투해 들어가면서 설계와 코드가 모두 지저분해짐
  • 이런 부가기능 코든는 여기저기 메서드에 마구 흩어져서 나타나고 코드는 중복됌
  • 런타임 시에는 각 부가기능 에스펙트는 자기가 필요한 위치에 다이내믹하게 참여
  • 하지만 설계와 개발은 다른 특성을 띤 에스펙트들을 독립적인 관점으로 작성
  • AOP는 에스펙트를 분리함으로써 핵심기능을 설계하고 구현할 때 객체지향적인 가치를 지킬 수 있도록 도와주는 것
  • 애플리케이션을 특정한 관점을 기준으로 바라볼 수 있게 해준다는 의미에서 관점 지향 프로그래밍이라고도 함

프록시를 이용한 AOP

  • 스프링은 다양한 기술을 조합해 AOP를 지원하는데 가장 핵심은 프록시를 이용한다는 것
  • 프록시로 만들어서 DI로 연결된 빈 사이에 적용해 타깃의 메서드를 호출 과정에 참여 해서 부가기능을 제공
  • 스프링 AOP의 부가기능을 담은 어드바이스가 적용되는 대상은 오브젝트의 메서드

바이트코드 생성과 조작을 통한 AOP

  • AspectJ는 컴파일된 타깃의 클래스 파일 자체를 수정하거나 JVM에 로딩되는 시점을 가로채서 바이트코드를 조작하는 방식을 사용
  • 이 때 장점은,
    1. DI 컨테이너의 도움을 받아서 자동 프록시 생성방식을 사용하지 않아도 AOP 적용 가능하기 때문에 컨테이너가 없는 환경에서도 AOP의 적용 가능
    2. 프록시 방식보다 훨씬 강력하고 유연한 AOP가 가능, 프록시는 부가기능을 부여할 대상은 클라이언트가 호출 할 떄 사용하는 메서드로 제한되지만, 바이트코드를 직접 조작하기 떄문에 오브젝트의 생성, 필드 값으 조회와 조작, static 초기화등의 다양한 작업에 부가기능 부여 가능

AOP 용어 정리

  • 타깃
    • 부가기능을 부여할 대상
  • 어드바이스
    • 타깃에게 제공할 부가기능을 담을 모듈
  • 조인 포인트
    • 어드바이스가 적용될 수 잇는 위치
    • 스프링 AOP의 조인 포인트는 메서드의 실행단계
    • 타깃 오브젝트가 구현한 인터페이스의 모든 메서드는 조인 포인트가 됌
  • 포인트컷
    • 어드바이스를 적용할 조인 포인트를 선별하는 작업 또는 그 기능을 정의한 모듈
    • 메서드의 시그니처를 비교하는 방법을 주로 사용
  • 프록시
    • 클라이언트와 타깃 사이에 투명하게 존재하면서 부가기능을 제공하는 오브젝트
  • 어드바이저
    • 포인트컷과 어드바이스를 하나씩 갖고 있는 오브젝트
    • 어떤 부가기능(어드바이스)를 어디에(포인트 컷) 전달할 것인가를 알고 있는 AOP의 가장 기본이 되는 모듈
  • 애스펙트
    • AOP의 기본 모듈
    • 한 개 또는 그 이상의 포인트 컷과 어드바이스를 조합
    • 보통 싱글톤 형태의 오브젝트

댓글 공유

팩토리

  • 객체의 생성 방법을 결정하고 그렇게 만들어진 오브젝트를 돌려주는 오브젝트
  • 디자인 패턴의 추상 팩토리 패턴이나 팩토리 메서드 패턴과는 다름
  • 오브젝트를 생성하는 쪽과 생성된 오브젝트를 사용하는 쪽의 역할과 책임을 분리하려는 목적으로 사용하는 것
  • 애플리케이션의 컴포넌트 역할을 하는 오브젝트와 애플리케이션의 구조를 결정하는 오브젝트를 분리한다는 데 의미가 있음

제어관계 역전

  • 일반적인 프로그램의 흐름은

    1. 프로그램의 시작지점(main method 등)에서 다음에 사용할 오브젝트 결정
    2. 결정한 오브젝트 생성
    3. 만들어진 오브젝트에 있는 메서드를 호출
    4. 메서드 안에서 다음에 사용할 것을 결정하고 호출
  • 이는 모든 오브젝트가 능동적으로 자신이 사용할 클래스를 결정

  • 언제 어떻게 그 오브젝트를 만들지를 스스로 관장

  • 모든 종류의 작업을 사용하는 쪽에서 제어하는 구조

  • 제어의 역전(Ioc)이란 이런 제어 흐름의 개념을 거꾸로 뒤집는 것

스프링 Ioc ApplicationContext 왜 사용?

  • 범용적이고 유연한 방법으로 Ioc 기능을 확장하기 위해
  1. 애플리케이션이 고도화되면 Ioc를 적용한 오브젝트도 계속 추가 될텐데 매번 어떤 팩토리 클래스를 사용해야 하는 지 알아야하고 필요할 때마다 팩토리 오브젝트를 생성해야하는 번거로움이 있음
    applicationContext는 알거나 직접 사용할 필요가 없고 일관된 방식으로 원하는 오브젝트를 가져올 수 있음

  2. 생성, 관계설정만 하는 것이 아닌 만들어지는 방식, 시점, 전략, 부가적으로 자동생성, 오브젝트에 대한 후 처리 등 효과적으로 활용할 수 있는 다양한 기능을 제공

  3. bean을 검색하는 다양한 방법을 제공


스프링 Ioc 용어 정리

빈(bean)

  • 스프링이 Ioc 방식으로 직접 그 생성과 제어를 담당하는 오브젝트

빈 팩토리(bean factory)

  • 스프링의 Ioc를 담당하는 핵심 컨테이너
  • 빈을 등록, 생성, 조회하고 돌려주고 부가적인 빈을 관리하는 기능을 담당
  • 보통 applicationContext를 사용

애플리케이션 컨텍스트(application context)

  • 빈 팩토리를 확장한 Ioc 컨테이너
  • 빈 팩토리에 스프링이 제공하는 각종 부가 서비스를 추가로 제공한 것

스프링이 싱글톤으로 빈을 생성하는 이유

  • 매번 클라이언트에서 요청이 올 때 마다 각 로직을 담당하는 오브젝트를 새로 만들어서 사용한다면 서버가 부하를 감당하기 어려움
  • 그래서 제한된 수(보통 한 개)의 오브젝트만 만들어서 사용하도록 싱클톤을 사용

Java 싱글톤 패턴의 한계

  1. private 생성자를 갖고 있기 때문에 상속 할 수 없음
  2. 초기화 과정에서 생성자 등을 통해 사용할 오브젝트를 다이나믹하게 주입하기도 힘들기 때문에 필요한 오브젝트는 직접 오브젝트를 만들어서 사용 할 수 밖에 없어 테스트가 힘듬
  3. 서버에서 클래스 로더를 어떻게 구성하고 있느냐에 따라 싱글톤 클래스여도 하나 이상의 오브젝트가 만들어질 수 있음
  4. 싱글톤의 static 메서드를 이용해 전역 상태로 사용되기 쉬우므로, 아무 객체나 자유롭게 접근하고 수정하고 공유할 수 잇는 전역 상태를 갖는 것은 객체지향 프로그래밍에서 권장되지 않음

싱글톤 레지스트리

  • 스프링에서 직접 싱글톤 형태의 오브젝트를 만들고 관리하는 기능

싱글톤 레지스트리의 장점

  • 오브젝트 생성에 대한 모든 권한은 Application Context에 있기 때문에 static 메서드와 private 생성자를 사용하는 것이 아닌 평범한 자바 클래스를 싱글톤으로 활용하게 해줌
  • 스프링이 빈을 싱글토으로 만드는 것은 결국 오브젝트의 생성 방법을 제어하는 Ioc 컨테이너로서의 역할

오브젝트의 상태

  • 멀티스레드 환경이라면 여러 스레드가 동시에 싱글톤에 접근해서 사용할 수 있으므로 상태 관리에 주의해야 함
  • 기본적으로 상태정보를 내부에 갖고 있지 않는 무상태 방식으로 생성되어야 함
  • 서로 값을 덮어쓰고자신이 저장하지 않은 값을 읽어올 수 있기 때문에 기본적으로 인스턴스 필드의 값을변경하고 유지하는 상태유지 방식으로 만들지 않음
  • 상태가 없는 방식으로 만드는 경우 생성한 정보는 파라미터와 지역변수, 리턴 값으로 이용함
  • 파라미터나 지역변수는 매번 새로운 값을 저장할 독립적인 공간이 만들어지기 때문에 싱글톤이라고 해도 여러 스레드가 변수의 값을 덮어 쓸일이 없음
  • 읽기전용 정보인 자신이 사용하는 다른 싱글톤 빈을 저장하려는 용도라면 인스턴스 변수를 사용해도 무방함

의존관계

  • A -> B 이면 B가 변하면 그것이 A에도 영향을 미친다는 것
  • 어린 자식은 부모에 의존적이므로 부모가 변하면 자식도 변하게 됨
  • 의존관계에는 방향성이 있음 (자식 -> 부모)
  • 자바에서는 Interface를 통해 의존관계를 줄일 수 있음, 이것이 낮은 결합도
  • 모델이나 코드에서 클래스와 인터페이스를 통해 드러나는 의존관계말고 런타임 시에 오브젝트 사이에서 만들어지는 의존관계도 있음
  • 런타임 의존관계 혹은 오브젝트 의존관계라고 함

의존 오브젝트

  • 프로그램이 시작되고 오브젝트가 만들어지고 런타임 시에 의존관계를 맺는 대상, 즉 실제 사용대상인 오브젝트

의존관계 주입

  • 구체적인 의존 오브젝트와 그것을 사용할 주체, 보통 클라이언트라고 부르는 오브젝트를 런타임 시에 연결해주는 작업
    1. 클래스 모델이나 코드에는 런타임 시점에 의존관계가 드러나지 않으므로 인터페이스에만 의존하고 있어야 함
    2. 런타임 시점의 의존관계는 컨테이너나 팩토리 같은 제 3의 존재가 결정
    3. 의존관계는 사용할 오브젝트에 대한 레퍼런스를 외부에서 제공(주입)해줌으로써 만들어짐
  • 핵심은 설계 시점에는 알지 못했던 두 오브젝트의 관계를 맺도록 도와주는 제 3의 존재가 있다는 것
    • application context
    • 빈 팩토리
    • Ioc 컨테이너 등

의존관계 검색

  • 외부로부터의 주입이 아니라, 스스로 검색
  • 런타임 시 의존관계를 맺을 오브젝트를 검색하는 것과 오브젝트의 생성 작업은 외부 컨테이너에게 Ioc로 맡기지만, 이를 가져올 떄는 메서드나 생성자를 통한 주입 대신 스스로 컨테이너에게 요청하는 방법을 사용
  • 미리 준비된 메서드를 호출하면 되니 단순히 요청으로 보이겠지만, 이런 작업을 일반화한 스프링의 application context라면 미리 정해놓은 일므을 전달해서 그 이림에 해당하는 오브젝트를 찾게 됨.
    • getBean()
  • 의존관계 검색 방식에서는 검색하는 오브젝트는 자신이 스프링의 빈일 필요가 없음
  • 반면 의존관계를 주입하기 위해선 생성과 초기화 권한을 갖고 있어야하고, 그러려면 Ioc 방식으로 컨테이너에서 생성되는 오브젝트, 즉 빈이어야 하기 때문

DI를 원하는 오브젝트는 먼저 자기 자신이 컨테이너가 관리하는 빈이 돼야 한다는 사실을 잊지 말자.

의존관계 주입의 장점

  1. 코드에는 런타임 클래스에 대한 의존관계가 나타나지 않음
  2. 인터페이스를 통해 결합도가 낮은 코드가 되므로 의존관계에 있는 대상이 바뀌거나 변경되더라도 자신이 영향 받지 않음
  3. 변경을 통한 다양한 확장에는 자유로움

1장 마무리

스프링이란, 어떻게 오브젝트가 설계되고, 만들어지고, 어떻게 관계를 맺고 사용되는 지에 관심을 갖는 프레임워크

댓글 공유

관심사 분리

  • 관심이 같은 것 끼리는 하나의 객체 안으로 또는 친한 객체로 모이게하고,
    관심이 다른 것은 가능한 따로 떨어져서 서로 영향을 주지 않도록 분리하는 것

템플릿 메서드 패턴

  • 슈퍼클래스에 기본적인 로직의 흐름을 만들고,
    그 기능의 일부를 추상 메서드나 오버라이딩 가능한 protected 메서드 등으로 만든 뒤 서브클래스에서 이런 메서드를 필요에 맞게 구현해서 사용하도록 하는 방법

팩토리 메서드 패턴

  • 서브클래스에서 구체적인 오브젝트 생성 방법을 결정하게 하는 것

중요한 건 디자인 패턴이 아닌 상속구조를 통해 성격이 다른 관심사항을
분리한 코드를 만들어내고, 서로 영향을 덜 주도록 했는지를 이해하는 것


상속을 통한 확장의 문제점

  1. 만약 다른 목적을 위해 이미 상속을 사용하고 있다면?

  2. 상속을 통한 상하위 클래스의 관계는 생각보다 밀접

  3. 서브클래스는 슈퍼클래스의 기능을 직접 사용할 수 있음
    그래서 슈퍼클래스 내부의 변경이 있을 때 모든 서브클래스를 함께 수정하거나 다시 개발해야 할 수도 있음
    반대로 그런 변화에 따른 불편을 주지 않기 위해 슈퍼클래스가 더 이상 변화하지 않도록 제약을 가해야 할지도 모름

추상 클래스를 만들고 이를 상속한 서브클래스에서
변화가 필요한 부분을 바꿔서 쓸수 있게 만든 이유는
변화의 성격이 다른 것을 분리해서 서로 영향을 주지 않은 채로
각각 필요한 시점에 독립적으로 변경할 수 있게 하기 위해서

그렇다면 아예 클래스로 따로 때 버린다면?

  • 코드로 새로 만든 클래스에 종속되어 버림
  • 상속 했을 때 처럼 코드 수정없이 기능을 변경할 방법이 없음

클래스를 통한 확장의 문제점

  1. 현재 a 메서드를 사용해 기능을 제공하고 있는데
    만약 a 메서드 대신 b 메서드를 사용하도록 수정 된다면
    일일이 a 메서드를 사용한 수십 수백개의 메서드를 수정해야 함

  2. 기능을 제공하는 클래스가 어떤 것인지 클라이언트가 구체적으로 알고 있어야 함
    만약 다른 클래스를 구현하면 또 클라이언트 자체를 수정해야 함

  3. 근본적인 원인은 클라이언트가 바뀔 수 있는 정보(db 커넥션 등)을 가져오는 클래스에 대해 너무 많이 알고 있기 때문

해결

  • 두 클래스가 서로 긴밀하게 연결되지 않도록 중간에 추상적인 연결고리를 만드는 것(java의 interface)

  • 클라이언트 입장에서는 인터페이스를 상속 받는 클래스의 오브젝트라면 어떤 클래스로 만들었건
    메서드를 호출하기만 하면 약속된 오브젝트를 만들어서 돌려줄 것으로 기대함


Interface를 통한 확장의 문제점

  1. 아직도 클래스의 생성자를 호출해서 오브젝트를 생성하는 코드가 남아있음

    • 초기에 한번 어떤 클래스의 오브젝트를 사용할지를 결정하는 생성자의 코드는 남아 있음
    • ex) conntion = new DConnectionMaker();
  2. 결국 클라이언트가 어떤 구현 클래스의 오브젝트를 이용하게 할지 결정하는 관심사가 남아 있음

해결

  • 오브젝트와 오브젝트 사이에 관계를 설정해야함

  • 오브젝트 사이의 관계는 런타임 시에 한쪽이 다른 오브젝트의 레퍼런스를 갖고 잇는 방식으로 만들어짐(보통 알고 있는 인스턴스 생성 방식)

    • ex)conntion = new DConnectionMaker();
    • DConnectionMaker의 오브젝트의 레퍼런스를 클라이언트의 connection 변수에 넣어서 사용하게 함

클래스 사이의 관계는 코드에 다른 클래스 이름이 나타나기 때문에 만들어지는 것

오브젝트 사이의 관계는 코드에서는 특정한 클래스를 전혀 알지 못하더라도 해당 클래스가 구현한 인터페이스를 사용했다면, 그 클래스의 오브젝트를 인터페이스 타입을 받아서 사용 할 수 있음

이것이 객체지향의 다형성


개방 폐쇄 원칙

  • 클래스나 모듈은 확장에는 열려 있어야하고 변경에는 닫혀 있어야 함

높은 응집도와 낮은 결합도

높은 응집도

  • 하나의 모듈, 클래스가 하나의 책임 또는 관심사에만 집중되어 있음
  • 작업은 항상 전체적으로 일어나고 무엇을 변경할지 명확하며, 그것이 클라이언트의 다른 로직에 수정을 요구하지 않을 뿐더라
    기능에 영향을 주지 않음
  • 변경이 일어난 경우에 이를 검증하려고 하면 변경한 구현 클래스만 직접 테스트 해보는 것으로 충분하기 때문
  • 응집도를 높인 덕분

낮은 결합도

  • 하나의 오브젝트가 변경이 일어날 떄에 관계를 맺고 잇는 다른 오브젝트에게 변화를 요구하는 정도
  • 하나의 변경이 발생할 때 여타 모듈과 객체로 변경에 대한 요구가 전파되지 않는 상태
  • 책임과 관심사가 다른 오브젝트 또는 모듈과는 낮은 결합도를 유지해야 함
  • 느슨하게 연결된 형태를 유지하는 것이 바람직
  • 꼭 필요한 최소한의 방법만 제공
  • 결합도가 낮아지면 대응하는 속도가 높아지고 구성이 깔금해짐

전략패턴

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

댓글 공유

  • page 1 of 1

Junggu Ji

author.bio


author.job