오브젝트 Object 요약 6~7

Mr_Gu·2022년 1월 17일
0

books

목록 보기
5/8
post-thumbnail

06.메시지와 인터페이스

Message

  • 객체끼리 협력하기 위해서는 서로 의사소통하는 수단이 필요하다. 메시지가 바로 이 수단에 해당한다.

  • 참고로 객체를 구현할 때 수신하는 메시지는 class 구현시 명시하기 때문에 신경 많이 쓰나 송신하는 메시지는 메서드의 구현 과정에 그냥 쓰고 생각 안하는 경우가 있다. 자기가 어떤 메시지를 송신하는 지도 고려하면서 협력 관계를 구축하자.

Interface

메시지, 오퍼레이션, 시그니처는 의사소통 과정을 각각 다른 관점에서 바라본 개념이다. 세 단어를 서로 바꿔가면서 써도 뤼앙스 차이만 느껴질 뿐 크게 이상하진 않다.

메시지 : 협력에 참여하는 전송자와 수신자를 모두 포함한 개념
오퍼레이션 : 객체가 다른 객체에게 제공하는 추상적인 서비스, 수신자의 관점만 다룸.
시그니처 : 오퍼레이션이나 메서드의 명세, 구현 관점 개념이다.

Interface 설계 품질

최소한의 인터페이스, 추상적인 인터페이스가 좋은 인터페이스다.
좋은 인터페이스, 좋은 협력 관계를 구축하기 위한 구체적인 룰이 몇 개 있다.

1) 디미터 법칙

협력 경로를 제한하는 규칙. 부끄럼 타는 코드를 작성하라. 아무 객체한테 요청하지 말고 특정 객체한테만 연락하자.

모든 클래스 C와 그 메서드 M에 대하여 M이 메시지를 전송할 수 있는 객체는 다음 C의 인스턴스여야 한다.
1) M의 인자로 들어온 Class
2) C의 인스턴스 변수 Class

  • this 객체
  • 메서드의 매개변수
  • this의 속성
  • this의 속성인 컬렉션의 요소
  • 메서드 내에서 생성된 지역 객체

2) 묻지말고 시켜라

묻는다는 행위 자체가 정보와 행위가 분리되었다는 소리다. 쿼리 인터페이스를 작성하기 전에 그냥 내가 결과를 도출해버리면 안되나 생각해보자.

3) 의도를 드러내는 인터페이스

인터페이스는 이해하기 쉽게 의도를 드러내야 한다. 반대로 인터페이스는 메시지의 목적을 제외한 나머지 부분은 철저히 감춰줘야 한다. 인터페이스 이름 정할 때 의도만 드러내고 동작 과정 같은 건 드러내지 말자. 개발은 이름 짓기 같다...

4) 명령 쿼리 분리하기

프로시저 : 부수 효과(State 변경)을 발생시키지만 리턴 값은 없다. Command라고도 부른다.
함수 : 부수 효과없이 리턴 값을 반환한다. Query라고도 부른다.

프로시저와 함수 둘을 구분하는 것은 매우 중요하다. 하나의 메서드가 두 개의 역할을 동시에 하게 하지 말자.

함수는 Side Effect가 없다는 특성 덕분에 최근에 각광받고 있다. functional programming, reactive programming은 함수의 참조 투영성을 기반으로 한다.

원칙에는 예외가 있다.

디미터 법칙은 Dot을 강제하는 규칙이 아니다.

IntStream.of(1, 15, 20, 3, 9).filter(x -> x > 10).distinct().count();

위의 코드는 계속 똑같은 객체를 반환했으며 해당 객체의 인터페이스만을 사용하였다. 디미터 법칙이 요구하는 범위의 객체하고만 통신했기에 규칙을 어긴게 아니다. 기차 충돌 형태 코드 자체는 문제가 아니다.

묻는 코드는 항상 나쁜가?

여러 객체를 포함하는 객체가 해당 객체들의 행동을 조율하는 경우 묻는 인터페이스가 없다면 결합도가 증가할 것이다. Movie가 Condition에게 조건을 묻고 Policy를 선택하는게 Policy와 Condition을 결합시키는 것보다 나은 선택이다.

결국은 책임

결국에는 책임을 제대로 분배했느냐의 이야기로 귀결된다. 원칙에는 항상 예외가 있기 때문에 설계를 도와주는 도구로 써야지 맹신하면 안된다. 그러니 저 위의 규칙들을 사용하면서도 항상 이 객체가 이 책임을 지는 것이 맞는지, 역할로 묶을 수 없는지를 고민하자.

계약에 의한 설계
인터페이스에는 해당 메시지의 실행 조건을 정의할 방법이 없다. 그래서 코드보면 메시지 호출은 송신자가 하는데 검증은 수신자가 하게된다. 이를 극복하기 위해 계약에 의한 설계 개념이 탄생하였다.


07. 객체 분해

사람은 복잡한 문제를 분해하거나 추상화하여 단기 기억의 적은 용량을 극복하였다. 프로그래밍 세계에서도 복잡성을 극복하는 방법은 똑같다.

기능 분해

추상적인 메인 로직이 구체적인 함수들에 의존하는게 가장 큰 문제다. 이로인해 생기는 문제는 다음과 같다.
1. 메인 함수의 빈번한 재설계
2. 비즈니스 로직과 UI의 강력한 결합
3. 변경 사항 생기면 Main까지 다 고쳐야 함.

그리고 사스템은 하나의 Main으로 이루어지지 않는다는 점도 기능 분해를 어렵게 한다. 기능 분해는 무언가를 창조할 때 사용하기보단 이미 어느정도 만들어진 로직을 정리할 때 효과적이다. (알고리즘 문제 풀기)

모듈

모듈은 변경 사항 생길 때 변경의 파급 효과를 가둘 방법을 제공한다. Module 내부는 데이터 값들과 해당 값들을 이용하는 메서드로 이루어져 있고 외부에는 자신이 노출하고 싶은 정보만 노출한다.

장점
전역 변수 오염 방지
모듈 내부의 변경이 모듈 내부로 한정된다.

한계점
데이터의 속성을 정의한게 아니라 값으로 가지고 있기에 인스턴스 생성이 불가능하다.
변경을 관리하기 위해 만든 거라 추상화 관점에선 한계점이 명확하다.

Abstract Data Type

Type : 변수에 저장할 수 있는 내용물 + 변수에 적용할 수 있는 연산의 가짓수
전통적인 기능 분해 방식의 한계를 깨닫고 등장한 데이터 추상화 개념의 일종이다.

Object

추상 데이터 타입 vs Object
Object: 다형성 지원, 데이터 중심으로 프로시저 추상화, 타입 기준으로 오퍼레이션을 묶는다.
Abstract Data Type : 다형성 지원 없음, 데이터 중심으로 타입을 추상화, 오퍼레이션 기준으로 타입을 묶는다.

추상화는 어떤 부분은 가리고 어떤 부분은 남기는 과정인거고 Abstract Data Type과 Object는 겉으로 보기에는 똑같은 Type을 남긴 것 같아도 드러내는 정보가 다른 듯 싶다. Object의 Type은 데이터 관련 정보는 더 숨기고 행동 관련 정보를 더 많이 드러낸 듯 싶다.
그냥 다형성 지원 여부가 차이점이라는 정도만 알아도 구별하는 데에는 문제 없다.

profile
그냥... 즐기자..

0개의 댓글

관련 채용 정보