kok202
오브젝트 05 ~ 08

2020. 3. 16. 22:35[공부] 독서/오브젝트

05 - 책임 할당하기

객체에게 중요한 것은 데이터가 아니라 외부에 제공하는 행동이다.[134p]

책임을 결정할 땐 메시지를 결정하고 메시지를 누구에게 전송할지 찾아보아라.[135p]

책임 주도 설계의 핵심은 책임을 결정한후 책임을 수행할 객체를 결정하는 것이다.[136p]

 

GRASP : 일반적인 책임 할당을 위한 패턴

  1. Information expert : 메시지를 수신할 적합한 객체는 누구인가? [139p]
  2. Low coupling : 낮은 결합도 [143p]
  3. High Cohesion : 높은 응집도 [143p]
  4. Creator : 어떤 객체에게는 다른 객체를 생성할 책임을 지게해야한다. [144p]
  5. Polymorphism : 타입에따라 변하는 행동이 있다면 타입을 분리하고 변화하는 행동을 각 타입의 책임으로 할당하라 [158p]
  6. Protected variations : 설계에서 변하는 것이 무엇인지 고려하고 변화하는 개념을 캡슐화하라 [159p]

 

응집도가 낮은 클래스의 징조 [152p]

  1. 클래스 생성 단계에 모든 속성이 초기화 되지 못한다.
  2. 메서드들이 사용하는 속성에 따라 그룹이 나뉜다.

 

변경을 염두한 설계 : 코드를 이해하고 수정하기 쉽게 설계하는 것

유연성을 염두한 설계 : 코드를 수정하지 않고도 변경을 수용할 수 있도록 코드를 설계하는 것 [163p]

 

RDD 가 어렵다면 리팩토링으로 해결하라

메소드가 장황하고 재사용하기 어려우며 이해가 어려운 메소드를 몬스터 메소드라고 한다. [168p]

 

리팩토링 과정

  1. 몬스터 메소드를 분리하여 응집도를 높여라. [169p]
  2. 메소드를 적절한 위치로 분배하라. [172p]
  3. 타입에 따라 행동이 변하는 부분이 존재한다면 다형성을 이용하라. [174p]

 

 

 

06 - 메시지와 인터페이스

myObject.do(argument)

메시지 : do(argument)

메시지 전송 : myObject.do(argument)

오퍼레이션 : do

메소드 : do 의 구현체 { }

 

메시지를 수신했을 때 실제로 실행되는 함수, 프로시저를 메소드라고 부른다.

메시지 전송시에는 어떤 메소드가 실행 될지 알 수 없다.

메시지와 메소드를 구분해야 메시지 전송자와 수신자를 느슨하게 결합 시킨다. [179p]

 

좋은 인터페이스 [181p]

  1. 최소한의 인터페이스
  2. 추상적인 인터페이스

 

퍼블릭 인터페이스가 지켜야할 원칙

  1. 디미터 법칙 : 오직 인접한 이웃하고만 이야기하라 (오직 하나의 도트만 사용하라) [183p]
    하나의 도트를 강제하는 것은 아니다. 메소드 체이닝이 있어도 체이닝이 반환하는 값이 소통하고 있는 같은 이웃이고 객체 내부구현이 드러나지 않는다면 괜찮다. [199p]
  2. 묻지 말고 시켜라 : 내부 구조를 묻는 것보다 객체에게 시키는게 좋다. [186p]
  3. 매소드의 이름은 의도를 들어내라 : 메소드의 이름은 어떻게 수행하는지보다 무엇을 수행하는 지를 드러내는게 좋다. [188p]
  4. 명령과 쿼리를 분리하라. [202p]
    명령은 객체의 상태를 변환 시키며 반환 값을 가지지 않는다.
    쿼리는 객체의 상태를 반환 시키며 상태를 변환 시키지 않는다.
    어떤 오퍼레이션도 명령이면서 동시에 쿼리여서는 안된다.

 

타입이름, 메소드이름, 인자이름이 모두 결합된것이 인터페이스다. 결과와 목적만을 포함하여 클래스와 오퍼레이션을 명명하라. [190p]

 

부수 효과 : 함수로 들어온 인자의 상태를 변경시키는 동작

불변성 : 부수 효과가 없어서 동일한 인자가 주어지면 항상 같은 값이 나오는 경우.

참조 투명성 : 어떤 표현식 e가 있을 때 e의 결과 값을 e가 나타나는 모든위치에 교체해도 결과가 바뀌지 않는 특정

 

사설) 불변성이라는 개념이 데이터에 적용되면 Immutable 데이터 (같은 주소값이라면 항상 같은 데이터) 라고 부르고, 함수에 적용되면 순수 함수 (같은 인자값이라면 항상 같은 반환값)라고 부른다.

 

 

 

07 - 객체 분해

절차 지향의 문제점 => 하향식 기능 분해를 하게된다.

하향식 기능 분해의 문제점 [226p]

  1. 시스템이 하나의 메인 함수로 구성된다.
  2. 요구사항이 변경되면 메인 함수를 빈번히 수정해야한다.
  3. 비즈니스 로직이 사용자 인터페이스와 강하게 결합된다.
  4. 너무 이른 시기에 함수들의 실행순서가 고정된다.
  5. 데이터 형식이 변경되면 파급효과가 예측이 안된다.

하향식 분해는 이미 해결된 알고리즘을 문서화, 서술하는데는 훌륭하지만 실제 커다란 소프트웨어 동작을 설계하는데 적합하지는 않다. [235p]

 

정보 은닉 : 시스템에서 자주 변경되는 부분을 덜 변경되는 안정적인 인터페이스 뒤로 감추는 것 [235p]

모듈 :  논리적인 개념, 쉽게 변경되지 않는 인터페이스를 퍼블릭으로 제공하여 정보 은닉을 하고 복잡성을 낮춰주는 것 [236p]

  • 모듈의 핵심은 데이터다. [239p]
  • 모듈은 인스턴스의 개념을 제공하지 않는다. [240p]
  • 그러므로 모듈은 한계가 명확하고 그래서 등장한 것 추상 데이터 타입이다.

 

클래스 != 추상 데이터 타입

클래스는 상속과 다형성을 지원한다.

추상 데이터 타입은 상속과 다형성을 지원한다.

추상 데이터 타입을 기반으로 하는 프로그래밍 패러다임은 객체 기반 프러그래밍이다. [245p]

 

클래스가 추상 데이터 타입의 개념을 따르는지 확인하는 가장 간단한 방법은 클래스 내부에 인스턴스의 타입을 표현하는 변수가 있는지 살피는 것이다. 이런 경우 높은 확률로 타입에 따른 분기 처리를 하고 있을 확률이 높다. 객체지향에서는 조건문을 다형성으로 대체한다. (Replace Type code with class) [250p]

 

 

 

08 - 의존성 관리하기

작고 응집도 높은 객체란 책임의 초점이 명확하고 한가지 일만 잘하는 객체다. [253p]

협력은 객체가 다른 객체에 대해 알 것을 강요한다. 그로인해 과도한 협력은 설계를 난해하게 할 수도 있다. [253p]

 

어떤 객체가 예정된 작업을 수행하기 위해 다른 객체를 필요한 경우 두 객체 사이에 의존성이 존재한다고 말한다. [254p]

의존하고 있는 객체가 다른 객체를 의존하는 경우를 의존성이 전이 될 수 있다. 

의존성이 실제로 전이될지 여부는 변경의 방향과 캡슐화 정도에 따라 다르다.

의존성은 전이될 수 있기 때문에 직접 의존성과 간접 의존성으로 나뉜다.[257p]

 

런타임 의존성은 런타임시 발생하는 객체 사이의 의존성이다.

컴파일 의존성은 코드 사이에 발생하는 클래스 사이의 의존성이다.[258p]

 

어떤 클래스의 인스턴스가 다양한 클래스의 인스턴스와 협력하기 위해서는 협력할 인스턴스의 구체적인 클래스를 알아서는 안된다. [260p]

클래스가 특정 문맥(클래스)에 강하게 결합되면 다른 문맥에서 사용하기 어려워진다.

그러므로 컨텍스트 독립성이 유지되어야한다.

컨텍스트 독립적이란 각 객체가 해당 객체를 실행하는 시스템에 관해서는 아무것도 알지 못하다는 의미다.[261p]

 

의존성을 해결하는 기법에는 크게 3가지가 있다. [261p]

  • 생성자를 통한 의존성 해결
  • Setter 를 통한 의존성 해결
  • 메소드 실행 인자를 통한 의존성 해결

사설) 여기나오는 기법들이 사실상 DI 기법들

 

의존성의 존재 보다는 의존성의 정도가 중요하다.

구체적인 클래스에 의존하는 경우 다른 종류를 사용할 재사용 가능성을 없애버린다. [265p]

이처럼 재사용성이 낮은 의존성을 가진 경우 강한 결합도를 가진다고 말한다.

반면 재사용성이 높은 의존성을 가진 경우 느슨한 결합도를 가진다고 말한다. [266p]

 

의존할 것이라면 추상화에 의존하라.

그리고 가능하면 인터페이스에 의존하라. [268p]

 

어떤 책임을 수행하는데 객체를 직접 생성하여 의존하는 경우를 숨겨진 의존성이라고 한다.

어떤 책임을 수행하는데 객체를 전달받아 의존하는 경우 명시정 의존성이라고한다. (의존성이 노출되므로) [270p]

 

new 는 해롭다. [271p]

  • new 연산자를 사용하면 구체 클래스의 이름을 직접 기술하므로 결합도가 올라간다.
  • new 연산자는 구체 클래스에 필요한 생성자에 대해서도 알아야한다.
    이로인해 클라이언트쪽에서는 알아야하는 지식의 양이 늘고 결합도가 높아진다.

단 가끔은 new 가 무방하기도하다 [274p]

 

표준 클래스에대한 의존은 해롭지 않다. 특히 ArrayList 와 같은 표준 라이브러리는 코드 수정이 될 확률이 0에 가깝기 때문에 더욱 그렇다. 다만 이런 경우에도 List 를 사용하는 등 추상화에 의존하는 것은 좋은 설계 습관이다. [276p]

 

시스템은 객체를 생성해 서로 메세지를 주고 받을 수 있게 조립하는 과정이다.

시스템의 행위는 객체의 조합을 통해 나타나는 특성이다.[281p]

 

 

 

'[공부] 독서 > 오브젝트' 카테고리의 다른 글

오브젝트 부록  (0) 2020.03.22
오브젝트 13 ~ 15  (0) 2020.03.19
오브젝트 09 ~ 12  (0) 2020.03.18
오브젝트 01 ~ 04  (0) 2020.03.15