시그마 삽질==six 시그마

리팩토링 2판(마틴 파울러) 본문

프로그래밍/Programming stuff

리팩토링 2판(마틴 파울러)

Ethan Matthew Hunt 2020. 10. 1. 10:48
리팩토링 2판 (저자: 마틴 파울러 ) 구입하시길 강력 추천드립니다.

리팩토링의 모든 것이 담겨있습니다.

책 구입을 원하시는분은 요기를 클릭하시면 됩니다.

하단의 내용은 제가 예전에 읽었던 내용을 제 나름대로 요약한 것으로 저자의 의도와는 다를 수 있습니다

 

CHAPTER 01 리팩터링: 첫 번째 예시

 

1.1 자, 시작해보자!

1.2 예시 프로그램을 본 소감

 

 

1.3 리팩터링의 첫 단계

리팩터링하기 전에 제대로 된 테스트부터 마련한다. 테스트트 반드시 자가진단하도록 만든다.

 

 

1.4 statement() 함수 쪼개기

 

아무리 간단한 수정이라도 리팩터링 후에는 항상 테스트를하는 습관을 들이는 것이 바람직하다

이처럼 조금씩 변경하고 매번 테스트하는 것은 리팩터링 절차의 핵심이다.

리팩터링은 프로그램 수정을 작은 단계로 나눠 진행한다. 그래서 중간에 실수하더라도 버그를 쉽게 찾을 수 있다.

 

하나의 리팩터링을 문제없이 끝낼 때마다 커밋한다. 그래야 중간에 문제가 생기더라도 이전의 정상 상태로 쉽게 돌아갈 수 있다. 이렇게 자잘한 변경들이 어느정도 의미있는단위로 뭉쳐지면 공유 저장소로 푸시한다.

컴퓨터가 이해하는 코드는 바보도 작성할 수 있다. 사람이 이해하도록 작성하는 프로그래머가 진정한 실력자다.

 

 

1.5 중간 점검: 난무하는 중첩 함수

1.6 계산 단계와 포맷팅 단계 분리하기

1.7 중간 점검: 두 파일(과 두 단계)로 분리됨

1.8 다형성을 활용해 계산 코드 재구성하기

1.9 상태 점검: 다형성을 활용하여 데이터 생성하기

 

1.10 마치며

좋은 코드를 가늠하는 확실한 방법은 얼마나 수정하기 쉬운가다

 

 

 

CHAPTER 02 리팩터링 원칙

 

2.1 리팩터링 정의

 

2.2 두 개의 모자

소프트웨어를 개발할 때  목적이 '기능 추가' 냐 아니면 '리팩터링'이냐를 명확히 구분해 작업한다. 켄트벡은 이를 두개의 모자에 비유했다.

 

2.3 리팩터링하는 이유

소프트웨어 설계가 좋아지고, 이해하기 쉬워지고,버그 쉽게 찾고 프로그래밍 속도를 높일 수 있다. ---> 설계 지구력 가설 : x축 시간, y축 기능의 누적  좋은설계는 y=x  나쁜설계는 기울기 처음에는 y=x 나중에는 y=1 

 

2.4 언제 리팩터링해야 할까?

라이브러리를 교체할때는 기존것과 새것을 모두 포용하는 추상 인터페이스부터 마련한다. 기존 코드가 이 추상인터페이스를 호출하도록 만들고 나면 라이브러리를 쉽게 갈아탈 수 있다.(이전략을 추상화 갈아타기라고 한다.)

https://martinfowler.com/bliki/BranchByAbstraction.html

 

2.5 리팩터링 시 고려할 문제

 

리팩터링의 궁극적인 목적은 개발 속도를 높여서, 더 적은 노력으로 더 많은 가치를 창출하는 것이다.

가장 위험한 오류는 리팩터링을 클린코드나 바람직한 엔지니어링 습관처럼 도덕적인 이유로 정당화 하는것이다. 

리팩토링의 본질은 코드 베이스를 예쁘게 꾸미는데 있지 않다. 

오로지 경제적인 이유로 하는것이다. 리팩토링은 개발기간을 단축하고자 하는것이다.

 

브랜치

독립 브랜치로 작업하는 기간이 길어질수록 작업 결과를 마스터로 통합하기가 어려워진다. 이 고통을 줄이고자 많은 이들이 마스터를 개인 브랜치로  수시로 리베이스 하거나 머지한다. 기능별 브랜치의 통합 주기를 2~3일 단위로 짧게 관리해야 한다고 주장하는 사람이 많다. 더 짧아야한다. 이 방식을 지속적 통합(CI) 또는 트렁크 기반 개발(TBD) 이라 한다. CI에 따르면 모든 팀원이 하루에 최소 한 번은 마스터와 통합한다.

 

https://martinfowler.com/articles/evodb.html

https://martinfowler.com/books/refactoringDatabases.html

 

2.6 리팩터링, 아키텍처, 애그니(YAGNI)

2.7 리팩터링과 소프트웨어 개발 프로세스

2.8 리팩터링과 성능

2.9 리팩터링의 유래

2.10 리팩터링 자동화

2.11 더 알고 싶다면

 

 

 

CHAPTER 03 코드에서 나는 악취

 

 

3.1 기이한 이름

3.2 중복 코드

3.3 긴 함수

3.4 긴 매개변수 목록

3.5 전역 데이터

3.6 가변 데이터

3.7 뒤엉킨 변경

3.8 산탄총 수술

3.9 기능 편애

3.10 데이터 뭉치

3.11 기본형 집착

 

3.12 반복되는 switch문

순수한 객 지향을 신봉하는 사람들과 얘기하다 보면 주제는 곧 switch 문의 사악함으로 흘러가기 마련이다. 이들은 코드에 등장하는 switch문을 모조리 조건부 로직을 다형성으로 바꾸기로 없애야할 대상이라고 주장한다.

 

3.13 반복문

3.14 성의 없는 요소

3.15 추측성 일반화

3.16 임시 필드

 

3.17 메시지 체인

get.get.get 게터가 꼬리를 물고 이어지는 코드가 있다. 이는 클라이언트가 객체 내비게이션 구조에 종속됐음을 의미한다. 그래서 내비게이션 중간 단계를 수정하면 클라이언트 코드도 수정해야한다.

위 문제는 위임 숨기길 해결한다

 

3.18 중개자

객체의 대표적인 기능 하나로, 외부로부터 세부사항을 숨겨주는 캡슐화가 있다. 캡슐화하는 과정에서는 위임이 자주활용된다. 하지만 지나치면 문제가 된다. 

 

3.19 내부자 거래

3.20 거대한 클래스

3.21 서로 다른 인터페이스의 대안 클래스들

3.22 데이터 클래스

3.23 상속 포기

3.24 주석

 

 

 

CHAPTER 04 테스트 구축하기

 

4.1 자가 테스트 코드의 가치

회귀버그를 잡는데 수월하다.

회귀버그란 잘 작동하던 기능에서 문제가 생기는 현상을 가르키며, 일반적으로 프로그램을 변경하는 중 뜻하지 않게 발생한다. 같은 맥락에서 잘 작동하던 기능이 여전히 잘 작동하는지 확인하는 테스트를 회귀테스트라한다.

 

 

4.2 테스트할 샘플 코드

4.3 첫 번째 테스트

 

4.4 테스트 추가하기

테스트는 위험 요인을 중심으로 작성해야 한다.

 

4.5 픽스처 수정하기

설정-실행-검증 setup-exercise-verify

조건-발생-결과 given-when-then

준비-수행-단언 arrange-act-assert

4.6 경계 조건 검사하기

4.7 끝나지 않은 여정

 

 

 

CHAPTER 05 리팩터링 카탈로그 보는 법

 

5.1 리팩터링 설명 형식

5.2 리팩터링 기법 선정 기준

 

 

 

CHAPTER 06 기본적인 리팩터링

 

6.1 함수 추출하기

코드를 언제 독립된 함수로 묶어야 할지에 관한 의견은 수없이 많다.목적과 구현을 분리하는 방식이 가장 합리적 기준으로 보인다.

함수안에 들어갈 코드가 대여섯줄을 넘어갈 때부터 슬슬 냄새가 풍기기 시작한다

 

만약 변수가 초기화되는 지점과 실제로 사용되는 지점이 떨어져 있다면 문장 슬라이드하기 (8.6)을 활용하여 변수 조작을 모두 한곳에 처리하도록 모아두면 편하다.

값을 반환할 변수가 여러 개라면? 개인적으로 함수가 값을 하나만 반환하는 방식을 선호하기 때문에 각각을 반환하는 함수 여러개로 만든다.

 

6.2 함수 인라인하기

때로는 함수 본문이 이름만큼 명확한 경우도 있다. 또는 함수 본문 코드를 이름만큼 깔끔하게 리팩터링할때도 있다. 이럴때는 그 함수를 제거한다.

 

6.3 변수 추출하기

복합한 로직을 구성하는 단계마다 이름을 붙일 수 있어서 코드의 목적을 훨씬 명확하게 드러낼 수 있다.

조잡한 식을 의미있는 변수명으로 추출

 

 

6.4 변수 인라인하기 

변수로 들어간 코드를 변수의 대입문 우변의 코드로 변경하기

 

 

6.5 함수 선언 바꾸기

(함수이름 바꾸기, 시그니처 바꾸기)

 

6.6 변수 캡슐화하기

클래스내에서 필드 직접 접근 대신 get,set 접근 메서드 만들기임

변수 간접 접근 방식 장점은 하위 클래스가 메서드에 해당 정보를 가져오는 방식을 재정할 수 있으며 데이터 관리(예: 속성 초기화를 생성 시점이 아닌 사용 시점으로 미루기)가 더 유연해지는 장점. 변수직접접근하기 장점은 코드를 더욱 알아보기 쉽다. 저자는 직접사용하다 간접필요시 간접으로 전환한다

 

데이터의 유효범위가 넓을수록 캡슐화해야한다. 레거시 코드를 다룰때는 이런 변수를 참조하는 코드를 추가하거나 변경할 때마다 최대한 캡슐화 한다. 그래야 자주 사용하는 데이터에 대한결합도가 높아지는 일을 막을 수 있다.

 

6.7 변수 이름 바꾸기

 

6.8 매개변수 객체 만들기

여러 매개변수(파라미터)들을 객체로 만들어서 넘기는거임.

데이터 항목 여러개가 이 함수에서 저 함수로 함께 몰려다니는 경우를 자주 본다. 난 이런 경우 데이터 무리를 발견하면 데이터 구조 하나로 모아주곤한다.

 

6.9 여러 함수를 클래스로 묶기

(흔히 함수 호출시 인수로 전달되는 ) 공통 데이터를 중심으로 긴밀하게 엮어 작동하는 함수 부리를 발견하면 클래스 하나로 묶고 싶어진다.

중첩함수보다 클래스를 선호하는 편인데 중첩함수는 테스트하기가 까다롭기때문. 또한 한 울타리로 묶을 함수들 중 외부에 공개할 함수가 여러개일때는 클래스를 사용할 수밖에 없다. 클래스를 지원하지 않는 언어를 사용할때는 같은 기능을 함수를 객체처럼 패턴(Function As Object)을 이용해 구현함

https://martinfowler.com/bliki/FunctionAsObject.html

 

6.10 여러 함수를 변환 함수로 묶기

저자는 본질은 같고 부가 정보만 덧붙이는 변환 함수의 이름은 "enrich"라 하고 형태가 변할때만 "transform"이라는 이름을 쓴다

 

6.11 단계 쪼개기

분리하는 가장 편한 방법 하나는 동작을 연이은 두 단계로 쪼개는 것이다. 본 작업에 들어가기 전에 입력값을 다루기 편하 형태로 가공한다. 아니면 로직을 순차적인 단계들로 분리해도 된다.

 

 

 

 

CHAPTER 07 캡슐화

 

 

7.1 레코드 캡슐화하기

저자는 가변 데이터를 저장하는 용도로는 레코드보다 객체를 선호한다.가변 데이터일때 객체를 선호한다.

 

 

7.2 컬렉션 캡슐화하기

컬렉션 변수로의 접근을 캡슐화하면서 게터가  컬렉션 자체를 반환하도록 한다면, 그 컬렉션을 감싼 클래스가 눈치채지 못하는 상태에서 컬렉션의 원소들이 바뀌어 버릴 수 있다. 

내부 컬렉션을 직접 수정하지 못하게 막는 방법 중 하나로, 절대로 컬렉션 값을 반환하지 않게 할 수 있다. 또 다른 방법으로는 컬렉션을 읽기전용으로 제공할 수 있다.

저자는 컬렉션에 대해서는 강박증을 갖고 불필요한 복제본을 만드는 편이 예상치 못한 수정이 촉발한 오류를 디버깅하느것보다 낫다함.

 

7.3 기본형을 객체로 바꾸기

단순한 출력 이상의 기능이 필요해지는 순간 그 데이터를 표현하는 전용 클래스를 정의하는 편

string 전화번호를 객체로..

 

7.4 임시 변수를 질의 함수로 바꾸기

,임시변수를 메서드 호출로 변환

변수 대신 함수로 만들어두면 비슷한 계산을 수행하는 다른 함수에서도 사용할 수 있어 코드 중복이 줄어든다.

이번 리팩토링은 클래스안에서 적용할때 효과가 가장 크다(클래스 안에서 private)

 

 

 

7.5 클래스 추출하기

클래스는 반드시 명확하게 추상화하고 소수의 주어진 역할만 처리해야한다는 가이드라인이있다.

메서드와 데이터가 너무 낳은 클래스는 이해하기 쉽지 않으니 잘 살펴보고 적절히 분리하는게 좋다. 

특히 일부 데이터와 메서드를 따로 묶을 수 있다면 어서 분리하라는 신호다.

함께 변경되는 일이 많거나 서로 의존하는 데이터들도 분리한다.

 

7.6 클래스 인라인하기

7.7 위임 숨기기

모듈호 설계를 제대로 하는 핵심은 캡슐화다.

캡슐화는 모듈들이 시스템의 다른 부분에 대해 알아야 할 내용을 줄여준다. 캡슐화가 잘 되어 있다면 무언가를 변경할때 함께 고려해야할 모듈 수가 적어져서 코드를 변경하기가 훨씬 쉬워진다.

 

예컨데 서버 객체의 필드가 가르키는 객체(위임객체)의 메서드를 호출하려면 클라이언트는 이 위임 객체를 알아야한다. 위임 객체의 인터페이스가 바뀌면 이 인터페이스를 사용하는 모든 클라이언트가 코드를 수정해야한다.

이러한 의존성을 없애려면 서버 자체의 위임 메서드를 만들어서 위임 객체의 존재를 숨기면 된다. 그러면 위임 객체가 수정되더라도 서버 코드만 고치면 되며, 클라이언트는 아무런 영향을 받지 않는다.

 

 A-->B--->C method 접근시

 

class A

B b

 

변경전 : a.getB().get_C_Method(); 

 

변경후:

 

get_C_Method(){

return b.get_C_Method();

}

 

class B

C c

 

 

7.8 중개자 제거하기

클라이언트가 위임 객체의 또 다른 기능을 사용하고 싶을때마다 서버에 위임 메서드를 추가해야하는데, 이렇게 기능을 추가하다 보면 단순히 전달만 하는 위임 메서드들이 점점 성가셔진다. 그러면 서버 클래스는 그저 중재자 역할로 전락하여 차라리 클라이언트가 위임 객체를 직접호출하는게 나을 수 있다.

디미터법칙을 너무 신봉할때 이런 현상이 나타난다. 디미터 법칙을 지키다보면 이 과정에서 위임 혹은 래퍼 메서드가 너무 늘어나는 등의 부작용이 있을 수 있으니 상황에 맞게 응용하는게 좋다

 

7.9 알고리즘 교체하기

 

 

 

 

 

CHAPTER 08 기능 이동

 

 

8.1 함수 옮기기

어떤 함수가 자신이 속한 모듈 A의 요소들보다 다른 모듈 B의 요소들을 더 많이 참조한다면 모듈 B로 옮겨줘야마땅하다

원래의 함수를 소스 함수source function이라 하고 복사해서 만든 새로운 함수를 타깃함수(target function)이라 한다

 

8.2 필드 옮기기

 

8.3 문장을 함수로 옮기기

 

8.4 문장을 호출한 곳으로 옮기기

함수는 프로그래머가 쌓아 올리는 추상화의 기본 빌딩 블록이다. 그런데 추상화라는 것이 그 경계를 항상 올바르게 긋기가 만만치 않다.

예컨데 여러 곳에서 사용하던 기능이 일부 호출자에게는 다르게 동작하도록 바뀌어야 한다면 이런 일이 벌어진다. 그렇다면 개발자는 달리잔 동작을 함수에서 꺼내 해당 호출자로 옮겨야 한다

 

 

8.5 인라인 코드를 함수 호출로 바꾸기

함수는 여러 동작을 하나로 묶어준다. 그리고 함수의 이름이 코드이 동작 방식보다 목적을 말해주기 때문에 함수를 활용하면 코드를 이해하기 쉬워진다.

함수추출하기(6.1)와의 차이는 인라인 코드를 대체할 함수가 이미 존재하느냐 여부다. 아직 없어서 새로 만들어야한다면 6.1함수추출하기고 이미 존재한다면 인라인 코드를 함수 호출로 바꾸기를 적용하면된다.

 

8.6 문장 슬라이드하기

관련된 코드끼리 모으는 작업은 다른 리팩토링(주로 함수 추출하기)의 준비단계로 자주 행해진다

if else에 동일 구문있으면 밖으로 슬라이딩시키기

조건문 밖으로 슬라이드할때는 중복 로직이 제거될것이고, 조건문 안으로 슬라이드할때는 반대로 중복로직이 추가될것이다.

 

 

8.7 반복문 쪼개기

종종 반복문 하나에서 두가지 일을 수행하는 모습을 본다. 이렇게 하면 반복문을 수항해야할 때마다 두가지 일 모두를 잘 이해하고 진행해야 한다. 반대로 각각의 반복문으로 분리해두면 수정할 동작 하나만이해하면된다.

반복문 쪼개기의 묘미는 그 가체가 아닌, 다음 단계로 가는 디딤돌 역할에 있다.

 

8.8 반복문을 파이프라인으로 바꾸기

컬렉션 파이프라인 얘기임.

 

 

8.9 죽은 코드 제거하기

이 코드들은 스스로 절대 호출되지 않으니 무시해도 되는 함사다라는 신호를 주지 않기때문에 운 나쁜 프로그래머는 이 코드의  동작을 이해하기 위해 시간낭비

우리에겐 버전관리 시스템있으니 사용할 날이 오면 다시 살려내면 된다

 

 

 

CHAPTER 09 데이터 조직화

 

 

9.1 변수 쪼개기

역할이 둘이상인 변수가 있다면 쪼개야한다. 예외는 없다.

같은 변수를 계속 덮어쓰면서 사용하지 마라

함수내에서  매개변수값에 몬가 대입하는 코드가 있을땐 매개변수 대신 임시변수를 사용하게 수정하자

 

매개변로의 값 대입은 매개 변수 foo의 값을 다른 객체참조로 변경한다는 의미

 

void aMethod(Object foo){

foo.modifyInSomeWay(); //괜찮다

foo=anotherObejct; //절대안된다

}

 

int dicount(int inputVal,int quantity, int yearToDate){

int result= inputVal;

if(inputVal >50) reuslt=-2;

}

 

 

 

 

9.2 필드 이름 바꾸기

 

9.3 파생 변수를 질의 함수로 바꾸기

가변데이터를 완전히 배제하긴 불가능할때 많지만, 가변데이터의 유효범위를 가능한 좁혀야한다.

효과가 좋은 방법으로, 값을 쉽게 계산해낼수 있는 변수들을 모두 제거할 수있다.

 

 

 

9.4 참조를 값으로 바꾸기

 

9.5 값을 참조로 바꾸기

 

9.6 매직 리터럴 바꾸기

 

 

 

 

CHAPTER 10 조건부 로직 간소화

 

 

10.1 조건문 분해하기

if 구문내의 쏘련말을 추출해서  의도를 살린 이름의 함수로 변경해주자

 

 

10.2 조건식 통합하기

 

10.3 중첩 조건문을 보호 구문으로 바꾸기

조건문은 주로 두가지 형태로 쓰인다. 참인 경로와 거짓인 경로 모두 정상 동작으로 이어지는 형태와, 한쪽만 정상인 형태다

두 형태는 의도하는 바다 다르므로 의도가 코드에 드라나야 한다. 두 경로 모두 정상 동작이라면 if/else   한쪽만 정상이라면 비정상 조건을 if에서 검사한다음 조건이 참이면(비정상이면)함수에서 빠져나온다. 두번째 검사형태를 흔히 보호구문이라고 한다.

보호 구문은 이건 이 함수의 핵심이 아니다. 이일이 일어나면 무언가 조치를 취한후 함수에서 빠져나온다 라고 이야기한다

 

 

 

 

10.4 조건부 로직을 다형성으로 바꾸기

 

메소드 속 case문...

case들을 다형성을 활용해 객체로 만들고 메소드는 각자 오버라이딩으로 변경. 그 후 case문을 없애버린다(곤충다리 하나씩 뜯어내듯이 case문도 하나씩 없애버림 ㅋ)

 

 

 

10.5 특이 케이스 추가하기

 

10.6 어서션 추가하기

 

10.7 제어 플래그를 탈출문으로 바꾸기

제어 플래그의 주 서식지는 반복문 안이다. break문이나 continue 문 활용에 익숙하지 않은 사람이 심어놓기도 하고, 함수의 return 문을 하나로 유지하고자 노력하는 사람이 심기도 한다. 모든 함수의 return문은 하나여야 한다고 주장하는 사람도 있지만 저자는 동의x

 

 

 

CHAPTER 11 API 리팩터링

 

11.1 질의 함수와 변경 함수 분리하기

우리는 외부에서 관찰할 수 있는 겉보기 부수효과가 전혀 없이 값을 반환해주는 함수를 추구해야한다. 이런 함수는 어느때건 원하는 만큼 호출해도 아무 문제가 없다.

겉보기 부수효과가 있는 함수와 없는 함수는 명확히 구분하는게 좋다. 이를위한 한 가지 방법은 질의 함수(읽기함수)는 모두 부수효과가 없어야한다는 규칙을 따르는 것이다. 이를 명령 질의 분리라한다.

저자는 값을 반환하면서 부수효과도 있는 함수를 발견하면 상태를 변경하는 부분과 질의하는 부분을 분리하려 시도한다.

 

 

11.2 함수 매개변수화하기

함수에 매개변수 추가해서 비슷한 중복함수 없애기

 

두 함수의 로직이 아주 비슷하고 단지 리터럴값만 다르다면, 그 다른 값만 매개변수로 받아 처리하는 함수 하나로 합쳐서 중복을 없앨수 있다.

 

 

11.3 플래그 인수 제거하기

함수에서 불리언 플래그 없애기

불리언 플래그는 코드를 읽는 이에게 뜻을 온전히 전달하지 못하기 때문에 더욱 좋지 못하다. 함수에 전달한 true의 의미가 대체 뭐란 말인가?

 

 

11.4 객체 통째로 넘기기

하나의 레코드에서 값 두어개를 가져와 인수로 넘기는 코드를 보면, 나는 그 값들 대신 레코드를 통째로 넘기고 함수 본문에서 필요한 값들을 꺼내 쓰도록 수정하곤한다.

레코드를 통째로 넘기면 변화에 대응하기 쉽다.

 

 

11.5 매개변수를 질의 함수로 바꾸기

피호출함수에서 생성 가능한걸 호출함수의 매개변수에 두지마라!!! 호출함수의 매개변수에 두는대신 피호출함수 로직에 녹여라

 

 

 

피호출 함수가 스스로 쉽게 결정할 수 있는 값을 매개변수로 건네는 것도 일종의 중복이다. 이런 함수를 호출할때 매개변수의 값은 호출자가 정하게 되는데, 이결정은 사실 하지 않아도 었던 일이니 의미없이 코드만 복잡해질 뿐이다.

 

매개변수를 제거하면 값을 결정하는 책임 주체가 달라진다. 매개변수가 있다면 결정 주체가 호출자가 되고, 매개변수가 없다면 피호출함수가 된다. 저자는 습관적으로 호출하는 쪽을 간소하게 만든다.

즉 책임 소재를 피호출 함수로 옮긴다는 뜻인데, 물론 피호출 함수가 그 역할을 수행하기에 적합할때만 그렇게 한다.

 

11.6 질의 함수를 매개변수로 바꾸기

참조를 풀어내는 책임을 호출자로 옮기는 것이다. 11.5와 반대의 경우다.

이런 상황 대부분은 코드의 의존관계를 바꾸려 할때 벌어진다. 예컨데 대상 함수가 더이상 (매개변수화하려는) 특정 원소에 의존하길 원치 않을때 일어난다

 

이 리팩토링을  수행하면 호출하는 쪽 코드는 전보다 다루기 어려워지는게 보통이다. 의존성을 모듈 밖으로 밀어낸다 함은 그 의존성을 처리하는 책임을 호출자에게 지운다는 뜻이기때문이다. 결합도를 낮춘 효과에대한 반대급부인 셈이다.

 

 

11.7 세터 제거하기

 

11.8 생성자를 팩터리 함수로 바꾸기

생성자를 팩토리 메서드로 전환을 실시해야 할 가장 확실한 상황은 분류 부호를 하위클래스로 바꿀 때 발생한다. 분류 부호를 사용해 작성한 객체가 있는데 현시점에서 하위 클래스가 필요해졌다. 어느 하위클래스를 사용할지는 분류 부호에 따라 달라진다. 

하지만 생성자는 요청된 객체의 인스턴스 반환만 할 수 있다. 따라서 생성자를 팩토리 메서드로 바꿔야한다.

 

 

11.9 함수를 명령으로 바꾸기

함수는 프로그래밍의 기본적인 빌딩 블록 중 하나다.

그런데 함수를 그 함수만을 위한 객체 안으로 캡슐화하면 더 유용해지는 상황이 있다. 이런 객체를 가르켜 '명령 객체' 혹은 단순히 명령이라한다. 명령 객체 대부분은 메서드 하나로 구성되며 이 메서드를 요청해 실행하는 것이 이 객체의 목적이다.

 

명령은 요청을 캡슐화한 객체로 디자인 패턴 중 명령 패턴에서 말하는 명령과 같다.

 

클래스 내부 함수가 지역변수때문에 메서드 추출이 힘들경우 그 메서드 자체를 객체로 전환해서 모든 지역변수를 필드로 만드는 초식있음.

 

 

한편 명령 질의 분리 원칙에서 등장하는 명령은 객체의 겉보기 상태를 변경하닌 메서드를 가르킨다. 이런 의미의 명령은 변경함수가 적합함

 

 

 

11.10 명령을 함수로 바꾸기

 

11.11 수정된 값 반환하기

데이터가 수정됨을 알려주는 좋은 방법이 있다. 변수를 갱신하는 함수라면 수정된 값을 반환하여 호출자가 그 값을 변수에 담아두도록하는 것이다.

 

 

11.12 오류 코드를 예외로 바꾸기

예외를 사용하면 오류 코드를 일일히 검사하거나 오류를 식별해 콜스택 위로 던지는 일을 신경쓰지 않아도 된다.

 

 

11.13 예외를 사전확인으로 바꾸기

뜻밖의 오류란 말 그대로 예외적으로 동작할때만 쓰여야한다. 함수 수행 시 문제가 될 수 있는 조건을 함수 호출 전에 검사할 수 있다면, 예외를 던지는 대신 호출하는 곳에서 조건을 검사하도록해야한다.

 

 

 

CHAPTER 12 상속 다루기

 

12.1 메서드 올리기

 

12.2 필드 올리기

 

12.3 생성자 본문 올리기

 

12.4 메서드 내리기

 

12.5 필드 내리기

 

12.6 타입 코드를 서브클래스로 바꾸기

소프트웨어 시스템에서는 비슷한 대상들을 특정 특성에 따라 구분해야할때가 자주 있다. 예컨데 직원을 담당업무로 구분하거나(엔지니어,관리자,영업자 등) 주문을 시급성으로 구분하기도 함(급함,보통..)

이런 일을 다루는 수단을는 타입코드 필드가 있다. 타입코드는 크포그래밍 언어에따라 열거형이나 심볼, 문자열,숫자 등으로 표현하며, 외부 서비스가 제공하는 데이터를 다루려할때 딸려오는 일이 흔하다.

타입 코드만으로도 특별히 불편한 상황은 별로 없지만, 그 이상의 무언가 필요할때가 있다.  그게 서비클래스를 말한다. 서브클래스는 첫째, 조건에따라 다르게 동작하는 다형성 제공 둘째, 특 정 타입에서만 의미가 있는 값을 사용하는 필드나 메서드가 있을때 발현된다.

 

 

12.7 서브클래스 제거하기

 

12.8 슈퍼클래스 추출하기

 

12.9 계층 합치기

 

12.10 서브클래스를 위임으로 바꾸기

상속은 한번만 사용가능. 무언가 달라져야 하는 이유가 여러개여도 상속에서는 그 중 단 하나의 이유만 선택해 기준으로 삼을 수 밖에 없다.

사람 객체동작을 나이대,소득수준에따라 달리하고 싶으면 서브클래스는 젋은이와 어르신 혹은 부자와 서민이 되어야 한다. 둘다 안된다.

또다른 문제로 상속은 클래스들의 관계를 아주 긴밀하게 결합한다. 부모를 수정하면 이미 존재하는 자식들의 기능을 해치기 쉽다. 

그래서 위임. 상속보다 결합도 약함.  

(클래스)상속보다는 (객체) 컴포지션을 사용하라. 저자는 상속사용했다가 안되면 컴포지션으로 변경함

상속,컴포지션 둘다 사용가능 ->전략,상태 패턴

 

 

 

12.11 슈퍼클래스를 위임으로 바꾸기

Comments