반응형
SOLID
- 객체지향 설계의 5가지 원칙
- SRP : 단일 책임 원칙
- 한 클래스는 하나의 책임만 가져야 한다.
- 클래스는 하나의 기능만 가지며, 어떤 변화에 의해 클래스를 변경 해야 하는 이유는 오직 하나뿐이어야 한다.
- SRP로 책임이 분명해지기 때문에, 변경에 의한 연쇄작용에서 자유로워 질 수 있다.
- 가독성 향상과 유지보수가 용이해진다.
- 실전에서는 쉽지 않지만 늘 상기해야 한다.
- OCP : 개방-폐쇄 원칙
- 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀있어야 한다.
- 변경을 위한 비용은 가능한 줄이고, 확장을 위한 비용은 극대화 한다.
- 요구사항의 변경이나 추가사항이 발생하더라도, 기존 구성요소에는 수정이 일어나지 않고, 기존 구성 요소를 쉽게 확장해서 재사용한다.
- 객체지향의 추상화와 다형성을 활용한다.
- LSP : 리스코프 치환 원칙
- 서브 타입은 언제나 기반 타입으로 교체할 수 있어야 한다.
- 서브 타입은 기반 타입이 약속한 규약 (접근제어자, 예외 포함)을 지켜야 한다.
- 클래스 상속, 인터페이스 상속을 이용해 확장성을 획득
- 다형성과 확장성을 극대화하기 위해 인터페이스를 사용하는 것이 더 좋다.
- 합성(composition)을 이용할 수도 있다.
- ISP : 인터페이스 분리 원칙
- 자신이 사용하지 않는 인터페이스는 구현하지 말아야 한다.
- 가능한 최소한의 인터페이스만 구현
- SRP가 클래스의 단일 책임이라면, ISP는 인터페이스의 단일 책임
- DIP : 의존성 역전 원칙
- 상위 모델은 하위 모델에 의존하면 안된다. 둘 다 추상화에 의존해야 한다.
- 실제 사용관계는 그대로지만, 추상화를 매개로 메시지를 주고 받으면서 관계를 느슨하게 한다.
*카드 결제 시스템을 구현한다고 가정했을 때 카드사별 조립을 위한 추상화가 필요하다. *
간결한 함수
public static String renderPageWithSetupsAndTeardowns(PageData pageData, boolean isSuite) {
boolean isTestPage = pageData.hasAttribute("Test");
if (isTestPage) {
WikiPage testPage = pageData.getWikiPage();
StringBuffer newPageContent = new StringBuffer();
includesSetupPages(testPage, newPageContent, isSuite);
newPageContent.append(pageData.getContent());
includeTeardownPages(testPage, newPageContent, isSuite);
pageData.setContent(newPageContent.toString());
}
return pageData.getHtml();
}
해당 코드는 함수가 길고, 여러가지 기능이 섞여있다.
public static String renderPageWithSetupsAndTeardowns(PageData pageData, boolean isSuite) {
if (isTestPage(pageData))
includeSetupAndTearDownPages(pageData, isSuite);
return pageData.getHtml();
}
작게 쪼갠다. 함수 내 추상화 수준을 동일하게 맞춘다.
public Money calculatePay(Employee e) throws InvalidEmployeeType {
switch (e.type) {
case COMMISSIONED:
return calculateCommissionPay(e);
case HOURLY :
return calculateHourlyPay(e);
default :
throws new InvalidEmployeeType(e.type);
}
}
한 메서드에서 계산도 하고, Money도 생성한다. 두가지 기능을 모두 하고 있는 상황은 적절하지 않다.
public abstract class Employee {
public abstract boolean isPayday();
public abstract Money calculatePay();
public abstract void deliveryPay(Money pay);
}
public interface EmployeeFactory {
public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType;
}
public class EmployeeFactoryImpl implements EmployeeFactory {
public Employee makeEmployee(EmployeeRecord r) thorws InvalidEmployeeType {
switch(r.type) {
// ... 이하동일
}
}
}
한 가지만 하기(SRP), 변경에 닫게 만들기 (OCP)를 적용하여 계산과, 타입관리를 분리하였고
타입에 대한 처리는 최대한 Factory 내에서만 처리할 수 있도록 적용
함수 인수
- 인수의 갯수는 0~2개가 적당하다.
- 3개 이상일 경우?
안전한 함수
- 안전한 함수란 부수 효과가 없는 함수를 의미한다.
- 부수효과 : 값을 반환하는 함수가 외부 상태를 변경하는 경우
Session.initialize()는 함수와 관계없는 외부 상태를 변경시킨다.
함수 리팩터링
테스트 과정을 거치면서 리팩터링 하자.
본 포스팅은 Clean Code (Robert C. Martin), 제로베이스-한달한권(클린코드)를 참고하여 작성하였습니다.
반응형