티스토리 뷰

책/Clean Code

10장 클래스

0307kjb 2022. 4. 9. 12:19

캡슐화

 

변수와 유틸리티 함수는 가능한 공개하지 않는 편이 낫지만 반드시 숨겨야 한다는 법칙이 없다. 그러나 비공개 상태를 유지할 온갖 방법을 강구해야 한다. 캡슐화를 풀어주는 결정은 언제나 최후의 보루이기 때문이다.

 

 

클래스는 작아야 한다?

 

함수의 경우 물리적인 행 수로 크기를 측정했지만, 클래스의 경우는 '클래스가 맡은 책임'을 세는 것이다.

클래스의 이름은 해당 클래스 책임을 기술해야 하며 실제로 작명은 클래스의 크기를 줄이는 첫 번째 관문이다.

간결한 이름이 떠오르지 않는다면 필경 클래스의 크기가 큰 것인데, Processor, Manager 등과 같이 모호한 단어가 있다면 클래스에다 여러 책임을 떠안겼다는 증거이다.

또한 클래스의 설명은 if, and, or, but을 사용하지 않고서 25단어 내외로 사용하는 것을 권장한다. 

그래서 SRP 원칙이 중요시 된다. 프로그래머의 소양은 돌아가는 소프트웨어에서 깨끗하고 체계적인 소프트웨어로 탈바꿈해야 한다. 즉 큰 클래스 몇 개 보다 단일 클래스 여럿으로 이뤄진 것이 바람직하다.

 

 

응집도

 

클래스는 인스턴스 변수 수가 작아야 한다. 각 클래스 메서드는 클래스 인스턴스 변수를 하나 이상 사용해야 한다. 일반적으로 메서드가 변수를 많이 사용하면 할수록 메서드와 클래스의 응집도가 높다. 모든 인스턴스 변수를 메서드마다 사용하는 클래스는 응집도가 가장 높다.

만약 몇몇 메서드만이 사용하는 인스턴스가 많아지는 경우에 십중팔구 클래스를 쪼개라는 신호인 것을 생각해야 한다.

 

 

변경하기 쉬운 클래스

 

public class sql{
    public String create();
    public String insert(Object[] fields);
    public String selectAll();
    public String select(Column column, String pattern);
    public String select(Criteria criteria);
    public String findByKey(String keyColumn, String keyValue);
}

이런식 보다는,

abstract public class sql{
	abstract public String generate();
}

public class CreateSql extends sql{
	...
}

public class InsertSql extends sql{
	...
}

public class SelectSql extends sql{
	...
}

public class SelectWithCriteriaSql extends sql{
	...
}

public class SelectWithMatchSql extends sql{
	...
}

이렇게 변환하면 SRP원칙 뿐만 아니라 OCP 원칙도 지원한다. 새로운 기능을 추가하거나 변경 시 최소한의 코드만 줄이게 되거나 시스템 확장할 뿐 기존 코드를 건드리지 않는 효과를 낳는다.

 

 

변경으로부터 격리

 

요구사항은 변하기 마련이다. 따라서 코드도 변하기 마련이다. 객체지향을 배울 때 구체적인 클래스와 추상적인 클래스가 있다고 배운다. 구체적인 클래스는 상세한 구현, 추상적인 클래스는 개념만 포함한다. 상세한 구현에 의존하는 클래스는 구현이 바뀌면 위험에 빠진다. 그래서 우리는 추상 클래스와 인터페이스를 통해 구현이 미치는 영향을 격리한다.

상세한 구현에 의존하는 코드는 테스트가 어렵다.

 

추상화 클래스/인터페이스를 통해 테스트용 클래스와 실제 사용할 클래스를 따로 만드는 것이다.

실제 몇 초마다 바뀌는 API 클래스를 통제하는 것은 어렵다. 그러나 고정된 값을 가진 테스트용으로 만든 클래스라면, 결합도도 낮추고 유연성과 재사용성을 높여준다. 결과 DIP 원칙(구체적인 것보다 추상적인 것에 의존해야 한다)을 지원하게 된다.

class Client{
	private ChangeAPI api;
    ...
}


interface ChangeAPI{
	State transport(int box_count);
}

FixedBoxCountAPI implements ChangeAPI{
	State transport(int box_count){
    	...
    }
}

RealChangeAPI implements ChangeAPI{
	State transport(int box_count){
    	...
    }
}

class ClientTest{
	private Client client;
	private FixedBoxCountAPI api;
    
    @Before
    private setUp(){
    	api = new FixedBoxCountAPI()
        api.fix("data");
    	Client new client(api);
    }
    
    ...
}

 

Client는 상세한 RealChangeAPI 클래스를 의존하는 것이 아닌 ChangeAPI를 의존한다. 추상적인 개념을 의존하여 구체적 사실을 모두 숨기는 것이 포인트다. 

' > Clean Code' 카테고리의 다른 글

9장 단위 테스트  (0) 2022.04.06
8장 경계  (0) 2022.04.04
6장 객체와 자료구조  (0) 2022.03.29
3장 함수  (0) 2021.12.02
2장 의미 있는 이름  (0) 2021.11.28
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함