back_Java_06

객체지향 생활 체조 원칙 9가지
한 메서드에 오직 한 단계의 들여쓰기만 한다.
else 예약어를 쓰지 않는다.
모든 원시 값과 문자열을 포장한다.
한 줄에 점을 하나만을 찍는다.
줄여쓰지 않는다(축약금지).
모든 엔티티를 작게 유지한다.
3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다.
일급 컬렉션을 쓴다
getter / setter / 프로퍼티를 쓰지 않는다.
1. 한 메서드에 오직 한 단계의 들여 쓰기만 한다.
WORST
class Board {
public String board() {
StringBuilder buf = new StringBuilder();
for (int i = 0l i < 10; i++) {
for (int j = 0; j < 10; j++) {
buf.append(data[i][j]);
}
buf.append("\n");
}
return buf.toString();
}
}
BETTER
class Board {
public String board() {
StringBuilder buf = new StringBuilder();
collectRows(buf);
return buf.toString();
}
private void collectRows(StringBuilder buf) {
for (int i = 0; i < 10; i++) {
collectRow(buf, i);
}
}
private void collectRaw(StringBuilder buf, int row) {
for (int i = 0; i 10; i++) {
buf.append(data[row][i]);
}
buf.append("\n");
}
}
2. else 예약어를 쓰지 않는다.
WORST
public void login(String username, String password) {
if (userRepository.isVald(username, password)) {
redirect("homepage");
} else {
addFlash("error" , "Bad credentials");
redirect("login");
}
}
BETTER
public void login(String username, String password) {
if (userRepository.isVald(username, password)) {
return redirect("homepage");
}
addFlash("error" , "Bad credentials");
return redirect("login");
}
자주 가능한 것은 아니지만, 반환문을 매개변수화 할 수 있도록 변수 도입도 가능하다.
public void login(String username, String password) {
String redirectRoute = "homepage";
if (!userRepository.isVald(username, password)) {
addFlash("error" , "Bad credentials");
redirectRoute = "login";
}
redirect(redirectRoute); // 최종적으로 두 로직 모두 여기로 전달됨
}
조건문을 정리하기 위해 다형성을 사용한다거나, Null Object, State 패턴, Strategy 패턴이 도움 될 수 있다.
3. 모든 원시값과 문자열을 포장한다.
안티 패턴 중에 하나인 Primitive Obsession 을 피하기 위해서다.
만약 당신이 사용하는 변수에 행동이 포함된다면, 캡슐화 하기를 적극 추천한다.
이를 DDD(도메인 주도 개발) 에서는 특히 VO(Value Object)라고 부른다.
4. 한줄에 점 하나만 찍는다.
보통 "메서드 호출을 연쇄적으로 연결해서는 안된다"라는 원칙이 존재한다.
하지만 Fluent Interface 를 만들 때는 적용되지 않으며, 메소드 체인 패턴(Builder 패턴 같은 경우) 를 구현하는 경우 적용되진 않는다.
단, 위의 경우를 제외하곤 보통 이 규칙을 준하는게 좋다.
5. 줄여 쓰지 않는다.
축약하지 말자 이름은...!
6. 모든 Entity를 작게 유지하라!
하나의 클래스는 50줄을 넘기지 않기를 권장하며, 하나의 Package는 10개 파일 담지를 않기로 권장한다.
이는 class 가 길면 읽기 어렵다는 생각도 담겨 있다.
7. 3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다.
지키기 어려운 규칙이지만, 응집도를 높이고 캡슐화 정도를 높혀준다.

왜 2개를 해야 하는가? 에서 원 글의 저자는 이러한 결론을 언급한다.
단일 인스턴스 변수만을 사용해 상태를 유지하는 class
2개의 개별 변수를 조화롭게 협력 시키는 class
8. 일급 컬렉션을 쓴다.
일급 컬렉션이란, 컬렉션을 포함하는 해당 class 컬렉션을 제외한 다른 멤버 변수를 포함하지 말아야 한다.
즉 예를 들면 Unit이라는 클래스가 존재하고, 이를 여러개 묶어
List<Unit>
단위로 사용하는 Units는 1급 컬렉션이 될 수 있다.각 컬렉션은 자체 클래스로 감싸지기 때문에, 이제 컬렉션과 관련된 행동은 1급 컬렉션을 통해 사용할 수 있다.
컬렉션의 모든 API 또한 open 하지 않게 되는 장점도 있으며, 이는 컬렉션이 add, delete, peek, sort 라는 API 를 지원하는데, 1급 컬렉션의 publi API 가 add, delete 뿐이라면 외부의 사용자는 오직 2가지 메서드를 사용하게 된다.
9. getter/setter/프로퍼티 를 쓰지 않는다.
핵심은 외부에서 어떤 행위를 결정하는게 아니라, 객체의 상태를 가져오는 정도라면 불가피하지만, 그렇지 않다면 한 객체의 상태에 기반한 모든 행동은 객체가 스스로 결정하도록 해야한다.
WORST
// Game
private int score;
public void setScore(int score) {
this.score = score;
}
public int getScore() {
return score;
}
//Usage
game.setScore(game.getScore() + ENEMY_DESTROYED_SCORE);
BETTER
// Game
public void addScore (int delta) {
score += delta;
}
//Usage
game.addScore(ENEMY_DESTROYED_SCORE);
절대 Setter 는 쓰지 말것
Last updated