중복 코드
•
한 클래스의 두 메서드 안에 같은 코드가 들어있는 경우 → 메서드 추출
•
한 클래스의 두 하위 클래스에 같은 코드가 있는 경우 → 메서드 추출 후 상향
•
경우에 따라 템플릿 메서드 형성을 시도
•
중복 코드가 메서드 가운데에 있다면 주변 메서드 추출을 해보자.
•
서로 상관없는 두 클래스 안에 중복 코드가 있을 때는 한 클래스 안의 중복 코드를 클래스 추출이나 모듈 추출을 적용해 제 3의 클래스나 모듈로 떼어낸 후 그것을 다른 클래스에서 호출하는 방법 or 메서드를 떼서, 클래스 간에 메시지를 전달.
장황한 메서드
•
짧은 메서드를 쓰려면, 기본적으로 메서드명을 잘 정해야한다.
◦
메서드명은 기능 수행 방식이 아니라 목적을 나타내는 이름으로 정함.
•
이를 위해서는 메서드를 훨씬 과감하게 쪼개야 함.
•
메서드에 매개변수와 임시변수가 많으면 메서드 추출을 실시하기가 까다로움. → 수많은 매개변수와 임시변수를 새로 만든 메서드의 매개변수로 넘겨야한다. 가독성 안 좋음
◦
따라서 임시 변수를 메서드 호출로 전환하던가, 임시변수를 메서드 체인으로 전환하도록.
◦
긴 매개변수는 매개변수 세트를 객체로 전환, 객체를 통째로 전달해보자
◦
이래도 임시변수와 매개변수가 너무 많을 때는 메서드를 메서드 객체로 전환하는 기법을 사용해보자.
•
조건문과 루프도 메서드로 빼야함.
◦
조건문을 추출하려면 조건문 쪼개기
◦
루프를 컬렉션 클로저 메서드로 전환을 실시한 후, 클로저 메서드 호출과 클로저 자체에 메서드 추출을 실시
방대한 클래스
•
인스턴스 변수가 너무 많으면 중복 코드가 존재하기 마련이다.
•
클래스 추출, 연관되있는 변수를 골라 클래스로 빼내자.
◦
클래스 안의 일부 변수가 접두어나 접미어가 같다면 하나의 클래스로 추출해보자.
•
하위클래스가 적절한거 같으면 하위클래스 추출을, 추출할 클래스가 대리자로 부적절할 거 같으면 모듈 추출을 하면 됨.
과다한 매개변수
•
원래는 필요한 모든 걸 매개변수로 전달해야했는데, 이제는 다른 객체에게 요청하면 된다.
•
따라서 모든 데이터를 전달하는 것보다, 모든 데이터를 가져올 수 있는 메서드만 전달하면 됨.
•
사용 가능한 방법, 매개변수 세트를 메서드로 전환, 객체를 통째로 전달, 매개변수 세트를 객체로 전환
•
예외적으로 호출되는 객체가 호출 객체에 의존하면 안 될 때
수정의 산발
•
한 클래스가 다양한 원인 때문에 다양한 방식으로 자주 수정될 때
•
새 데이터베이스를 생성할 때마다 이 3개의 메서드를 수정해야하고, 새 금융 상품을 추가할 때마다 4개의 메서드를 수정해야하네 라는 생각이 든다면, 여러 개의 변형 객체로 분리하는 것이 좋다.
기능의 산재
•
수정의 산발과 비슷하지만 정 반대
•
수정할 때 여러 클래스에서 수많은 자잘한 부분을 고쳐야한다면 이 문제를 의심.
•
수정할 부분이 여기 저기 있다면 힘들다.
•
메서드 이동, 필드 이동을 적용해서 수정할 부분들을 전부 하나의 클래스로 넣어야함.
잘못된 소속
객체의 핵심 - 데이터와 그 데이터에 사용되는 프로세스를 한 데 묶는 기술
•
어떤 메서드가 자신이 속하지 않은 클래스에 더 많이 접근한다면 잘못된 소속의 구린내가 풍긴다.
•
소속이 잘못된 메서드가 흔히 접근하는 대상은 데이터
◦
다른 객체 있는 읽기 메서드를 자주 호출한다면, 더 자주 접근하는 클래스로 옮겨야하지 않을까?
◦
메서드 이동을 하거나, 메서드의 일부분만 소속이 잘못됬다면, 메서드를 추출후에 메서드 이동을 시킨다.
데이터 뭉치
•
동일한 데이터 항목이 여러 위치에 몰려 있을 수 있다.
◦
몰려 있다면 객체로 만들어야한다.
◦
필드들을 대상으로 클래스 추출 기법
강박적 기본 타입 사용
•
기본 타입은 아무런 기능도 제공하지 못한다. 돈이나 우편 번호 등도 객체로 전환해 관리하면 더 편한다.
switch 문
•
객체 지향 코드에서는 switch-case 문이 적게 사용된다.
•
switch문은 무조건 중복을 발생시킨다.
•
객체지향의 재정의를 사용하는게 무조건 좋다.
•
switch 문은 고민할 필요없이 재정의로 바꿔야한다.
◦
switch 문을 돌릴 데이터가 필요한데, 이 값은 메서드나 클래스 안에 들어가 있을 것.
◦
메서드 추출을 실시해서 switch문을 일단 메서드로 빼내고, 분류 부호가 있는 클래스로 메서드를 이동한 다음
◦
분류부호를 하위 클래스로 전환하고, 상태/전략 패턴으로 전환한다.
◦
상속 구조라면 조건문을 재정의로 전환
•
하나의 메서드에 영향을 미치는 case문이 2~3개 밖에 없고, 나중에 모든 case문을 수정할 일이 없으면 재정의로 전환하는 건 과하다.
◦
매개변수를 메서드로 변환하는 것이 낫다.
•
조건문이 있는 여러 case문 중 하나가 널일 때는 Null 검사를 널 객체에 위임을 실시하면 된다.
평행 상속 계층
기능의 산재의 특수한 상황
한 클래스의 하위 클래스를 만들 때마다, 매번 다른 클래스의 하위 클래스도 만들어야한다.
서로 다른 두 상속 계층의 클래스명 접두어가 같으면 이 문제를 의심할 수 있다.
직무유기 클래스
•
비용 대비 효율성이 떨어진다면 제거해야 함.
•
하위 클래스나 모듈의 경우에는 계층 병합해야함.
막연한 범용 코드
아직은 필요 없는 기능을 수행하고자 온갖 호출과 case문을 넣으려하는 순간 범용 코드의 구린내가 풍긴다.
•
별다른 기능이 없는 클래스나 모듈은 계층 병합
•
불필요한 위임을 제거하려면 클래스 내용 직접 삽입
•
메서드에 사용되지 않은 매개변수가 있으면 매개변수 제거
•
메서드명이 이상하다면 메서드명 변경
임시 필드
•
특정 상황에서만 할당되는 필드가 있으면 안 된다.
•
떠돌이 변수들을 마련해주려면 클래스 추출을 실시
•
Null 검사를 널 객체에 위임을 실시해서 그 변수들의 값이 올바르지 않을 경우를 대비한 대체 컴포넌트 작성하면 경우에 따라 조건문 삭제 가능
메시지 체인
메시지 체인은 클라이언트가 1번에게, 1번이 2번에게, 2번이 3번에게 객체를 요청하는 연쇄적 요청을 얘기함.
그 사이의 관계들을 수정할 때마다 클라이언트도 수정된다.
•
대리 객체 은폐를 실시해야함. ⇒ 일단은 보기에 체인을 끊어내는게 목적인듯.
과잉 중개 메서드
•
어떤 클래스의 인터페이스를 보니, 절반도 넘는 메서드가 기능을 다른 클래스에 위임한다면 실시하자.
•
가능한 방법들
◦
과잉 중개 메서드 제거 ⇒ 원리가 구현된 객체에 직접 접근
◦
메서드들의 내용을 호출 객체에 직접 삽입해도 된다.
◦
부수적인 기능이 있다면 위임을 상속으로 전환 기법을 사용
지나친 관여
•
지나치게 밀접한 나머지, 서로의 private을 알아내느라 과도한 시간 낭비를 할 때가 있다.
•
메서드 이동과 필드 이동을 실시해서 관여를 끊어놔야함.
•
클래스의 양방향 연결을 단방향으로 전환
•
공통으로 필요한 부분이 있다면, 클래스 추출을 사용해서 별도의 안전한 클래스로 빼내면 됨.
•
대리 객체 은폐를 실시하여 중계 메서드 역할을 하게 만들어도 됨.
•
상속으로 인해 지나친 관여가 발생하는 경우가 많다. 상위클래스에서 하위 클래스를 빼내야할 경우에는 상속을 위임으로 전환 기법을 적용하자.
인터페이스가 다른 대용 클래스
•
기능은 같은데 시그니처가 다른 메서드에는 메서드명 변경을 실시
미흡한 라이브러리 클래스
•
라이브러리 클래스에 넣어야할 메서드가 두 개뿐이라면 외래 클래스에 메서드 추가 기법을 실시
•
부가 기능이 많다면 국소적 상속확장 클래스 사용 기법을 실시
데이터 클래스
•
필드와 읽기,쓰기 메서드만 들어있는 클래스
•
오직 데이터 보관만 담당한다.
•
필드 캡슐화를 진행하자. 컬렉션 필드가 있으면 그 필드가 적절히 캡슐화되어있는지 확인하여 캡슐화되어있지 않다면 컬렉션 캡슐화 기법을 적용.
•
또는 쓰기 메서드 제거를 적용
•
또는 메서드 이동을 실시하여 기능을 그 데이터 클래스로 이동.
•
메서드 전체를 옮길 수 없다면 메서드 추출을 실시해서 옮길 수 있는 것만 이동
방치된 상속물
•
상속을 받았으나 사용하지 않는 경우
•
잘못된 계층 구조 때문이라고 설명할 수 있고, 메서드 하향, 필드 하향을 실시해서 합쳐야 함.
불필요한 주석
•
주석은 불필요하다. 주석이 없이도 설명가능해야함.