Replace State-Altering Conditionals with State
어떤 객체의 상태 전이를 제어하는 조건 로직이 복잡하다면, 각 상태에 해당하는 스테이트(state) 클래스를 하나씩 만들고 그들이 스스로 다른 상태로 전이하는 것을 책임지도록 하여 복잡한 조건 로직을 제거한다.
- snippet.java
abstract class PermissionState{ public String toString(); public void claimBy(SystemAdmin admin, SystemPermission permission){} public void deniedBy(SystemAdmin admin, SystemPermission permission){} public void grantedBy(SystemAdmin admin, SystemPermission permission){} }
- snippet.java
class PermissionClaimed extends PermissionState { public void deniedBy(SystemAdmin admin, SystemPermission permission){ if (!permission.getAdmin().equals(admin)) return; permission.setIsGranted(false); permission.setIsUnixPermissionGranted(false); permission.setState(DENIED); permission.notifyUserOfPermissionRequestResult(); } public void grantedBy(SystemAdmin admin, SystemPermission permission){ if (!permission.getAdmin().equlas(admin)) return; if (permission.getProfile().isUnixPermissionRequired() && !permission.isUnixPermissionGranted()){ permission.setState(UNIX_REQUESTED); permission.notifyUnixAdminsOfPermissionRequest(); return; } permission.setState(GRANTED); permission.setIsGranted(true); permission.notifyUserOfPermissionRequestResult(); } }
Move Embellishment to Decorator
어떤 클래스에 핵심 기능을 위한 코드와 꾸밈 코드가 뒤섞여 있으면, 꾸민 코드를 Decorator 로 옮긴다.
데코레이터는 공유할 수 없다. 데코레이터는 각각 자신이 꾸밀 객체를 참조하고 있기 때문이다. 반면에 스트레티지는 singlethon 이나 flyweight 패턴을 통해서 쉽게 공유할 수 있다. 스트레티지 클래스의 인터페이스는 자유롭게 구성할 수 있는 반면, 데코레이터 클래스는 호스트 클래스의 인터페이스에 맞춰야 한다. 데코레이터는 호스트 클래스와 인터페이스를 공유하는 한 호스트 클래스에 영향을 끼치지 않고 기능을 추가할 수 있다. 반면, 스트레티지를 사용하는 클래스는 스트레티지의 존재와 사용법을 알아야 한다. Strategy 패턴을 적용할 때는 호스트 클래스에 데이터나 public 메서드가 많다고 해서 장애가 되지 않는다. 그러나 호스트 클래스에 Decorator 패턴을 적용한다면, 데코레이터 클래스가 무거워지고 지나치게 많은 메모리가 필요하게 될 것이다.
�
��떤 패턴이 아무리 맘에 들더라도 정말 필요한 경우에만 사용해야 한다.
Replace Conditional Login with Strategy
메서드 내의 조건문을 통해 여러 개의 서로 다른 로직(계산법) 가운데 어떤 것을 실행할지 선택하고 있다면, 각 계산법에 대응하는 Strategy 클래스를 만들고 해당 Strategy 인스턴스에 계산을 위임하도록 메서드를 수정한다.
### Compose Method
어떤 메서드의 내부 로직이 한 눈에 이해하기 어렵다면, 그 로직을 의도가 잘 드러나며 동등한 수준의 작업을 하는 여러 단계로 나눈다.
이 리팩터링을 완료하고 나면, Composed Method에서 호출하는 작은 private 메서드가 여러 개 생길 것이다.
Compose Method 리팩터링은 메서드를 구현할 때 그 메서드가 무슨 일을 하며 그 일을 어떻게 처리하는지 효과적으로 드러나게 도와주는 리팩터링이다.
Inline Singleton
코드의 여러 곳에서 접근할 수 있어야 하지만 전역적일 필요까지는 없는 객체가 싱글턴^singleton^으로 구현되어 있다면, 싱글턴 객체를 저장하고 그에 대한 접근 경로를 제공하는 클래스로 싱글턴의 기능을 옮긴다. 그리고 싱글턴은 제거한다.
### Encapsulate Composite with Builder
컴포짓^composite^ 구조를 생성하는 과정이 반복적으로 수행되고 복잡하며 에러 발생 가능성도 많은 상태라면, 그 세부 사항을 처리하는 별도의 빌더^builder^를 제공하여 컴포짓 구조를 쉽게 생성할 수 있도록 한다.
### Introduce Polymorphic Creation with Factory Method
한 상속 구조 내의 클래스들이 어떤 메서드를 각자 구현하는데 객체 생성 단계만 제외하고 나머지가 서로 유사하다면, 그 메서드를 수퍼클래스로 옮기고 객체 생성은 팩터리 메서드^facotry method^에 맡기도록 한다.
### Encapsulate Classes with Factory
클라이언트가 한 패키지 내의, 공통 인터페이스를 가지는 클래스들의 인스턴스를 직접 생성하고 있다면, 그 클래스의 생성자를 클라이언트가 직접 볼 수 없게 바꾸고 클라이언트는 팩터리^factory^를 통해 그 인스턴스를 얻도록 한다.
Program to an interface, not an implementation
Move Creation Knowledge to Factory
어떤 클래스의 인스턴스를 생성하는데 사용되는 데이터와 코드가 여러 클래스에 퍼져 있다면, 그 생성 지식^createion knowledge^을 하나의 팩터리^factory^ 클래스로 옮긴다.
### Replace Constructors with Creation Methods
어떤 클래스의 인스턴스를 생성할 때 그것이 제공하는 여러 생성자 중 어떤 것을 호출해야 할지 결정하기가 어렵다면, 인스턴스를 생성해 리턴하는 생성 메서드^creation method^로 각 생성자를 대체하여 그 용도가 명확히 드러나도록 한다.
생성자 대신에 static method
로 생성 메서드를 제공한다.