깨끗한 클래스

깨끗한 클래스의 조건
클래스 정의를 깨끗하게 해야 한다
- 필드 정의 순서
- 변수목록이 먼저 나와야 한다.
public static
private static
private
public
필드는 지양한다.
- 변수목록이 먼저 나와야 한다.
- 메서드 정의 순서
public
메서드private
메서드는 자신을 호출하는public
메서드 직후에 정의하여, 순차적으로 읽힐 수 있도록 한다
- 캡슐화
- 필드와 메서드는 최대한 비공개 상태로 유지하여 캡슐화를 지킨다
eslint 같은 도구를 활용해서 IDE가 자동으로 정리해줄 수 있게 하자.
클래스는 작아야 한다
- 하나의 클래스는 하나의 책임을 가져야 한다
- 책임이 여러개인지 확인하는 방법
- 클래스 이름이 명확해야 한다 : 클래스 이름이 모호해진다면, 책임이 많아서 그렇게 된 경우다.
- 클래스 설명을 짧게 할 수 있어야 한다 : 클래스 설명을 25단어 내외로, 접속사 없이 가능해야 한다.
- 단일 책임 원칙 : 클래스는 변경할 이유가 하나뿐이여야 한다.
- 응집도
- 클래스는 자신과 관련된 일만 해야 한다
왜 클래스를 작게 만들어야 할까?
- 변경을 쉽게 하기 위해서
- 변경할 클래스를 쉽게 찾을 수 있고, 변경했을 때 문제가 생길 위험을 낮춰준다
변경하기 쉬운 클래스 만들기
시스템은 지속적으로 변경이 가해진다. 깨끗한 클래스는 변경에서 생길 수 있는 위험을 낮춰준다.
예를 들어, Lamp
클래스를 켜고 끌 수 있는 Switch
클래스가 있다고 생각해보자. 대략적인 코드는 아래와 같다.
class Switch {
lamp: Lamp
constructor(lamp: Lamp) {
this.lamp = lamp
}
on() {
this.lamp.activate()
}
off() {
this.lamp.deactivate()
}
}
class Lamp {
activate() {
// ...
}
deactivate() {
// ...
}
}
ts이런 상황에서 Switch
클래스는 다음과 같은 문제점이 있다.
- 구체 클래스인
Lamp
에 의존한다. 즉, 다른 클래스와 결합도가 높다 Lamp
를 다른 클래스로 교체하기 어렵다- 테스트하기 어렵다
구체 클래스가 아니라 추상화에 의존하는 방법으로 개선할 수 있다.
먼저, 켜고 끄는 API를 제공하는 인터페이스 Switchable
을 추가한다.
interface Switchable {
activate(): void
deactivate(): void
}
ts그리고 Lamp
는 Switchable
을 구현하도록 하고,
class Lamp implements Switchable {
// ...
}
tsSwitch
는 Swticable
을 주입받도록 변경한다.
class Switch {
switchable: Switchable
constructor(switchable: Switchable) {
this.switchable = switchable
}
public on() {
this.switchable.activate()
}
public off() {
this.switchable.deactivate()
}
}
ts그 결과, Switch
클래스는 변경하기 쉬워졌다.
- 구체 클래스가 아니라 추상화(인터페이스)에 의존하게 되었다
- Lamp 클래스와 결합도가 낮아졌다
- Lamp 클래스의 변경에 영향을 받지 않게 되었다
- 의존성을 외부에서 주입받게 되었으므로, 의존성을 교체하는 것이 쉬워졌다
- 테스트용 Switable을 만들어서 테스트하는 것도 가능하다