2023. 12. 3. 20:11ㆍ객체지향
class Money {
#amount;
#currency;
}
다음과 같은 전형적인 데이터 클래스가 존재한다고 생각하자.
생성자로 확실하게 정상적인 값 설정하기
다른 클래스에서 해당 데이터의 초기화를 하지 않도록 하기 위해서는 constructor
에 파라미터로 값을 전달하면 된다.
class Money {
#amount;
#currency;
constructor(amount, currency) {
this.#amount = amount;
this.#currency = currency;
}
}
가드 활용하기
하지만 잘못된 값이 전달될 수 있다.
이럴 때는 가드
를 활용해서 잘못된 요소를 메서드 앞부분에 제외할 수 있으므로 이어지는 로직이 간단해진다.
가드를 활용하면 잘못된 값을 가진 인스턴스가 존재할 수 없게 된다.
class Money {
#amount;
#currency;
constructor(amount, currency) {
this.#validateAmount(amount);
this.#validateCurrency(currency);
this.#amount = amount;
this.#currency = currency;
}
#validateAmount(amount) {
if (amount < 0) {
throw new Error('금액은 0 이상의 값을 지정해주세요.');
}
}
#validateCurrency(currency) {
if (currency === null) {
throw new Error('통화 단위를 올바르게 지정해주세요.');
}
}
}
응집도를 높이기
데이터와 데이터를 조작하는 로직이 분리되어 있으면 응집도가 낮은 구조라고 한다.
응집도가 낮다는 것은 데이터를 처리하는 로직이 여러 클래스에서 구현될 가능성이 높다는 것이다. 이것은 후에 리팩터링에 어려움을 겪을 수 있고, 코드 중복이 생길 수 있다.
따라서 계산로직도 클래스 내부에서 구현하여 응집도를 높인다.
class Money {
#amount;
#currency;
constructor(amount, currency) {
this.#validateAmount(amount);
this.#validateCurrency(currency);
this.#amount = amount;
this.#currency = currency;
}
add(other) {
this.#amount += other;
}
#validateAmount(amount) {
if (amount < 0) {
throw new Error('금액은 0 이상의 값을 지정해주세요.');
}
}
#validateCurrency(currency) {
if (currency === null) {
throw new Error('통화 단위를 올바르게 지정해주세요.');
}
}
}
인스턴스 변수를 불변 변수로 만들기
인스턴스 변수가 계속 바뀌게 되면 값이 언제 변경되었는지, 지금 값은 무엇인지에 대해 계속 신경써야한다.
또한 의도하지 않은 값을 할당하는 예상치못한 부수효과가 발생할 수 있다.
예를 들어 위의 코드에서 amount
가 500인데 add
메서드의 파라미터로 -600을 넣는다고 가정해보자.
금액은 0 이상의 값이어야 하지만 음수가 된다. 가드에서 유효성검사를 거치지도 않는다.
이럴때는 새로운 인스턴스를 반환하도록 수정하자.
add(other) {
const added = this.#amount + other;
return new Money(added, this.#currency);
}
엉뚱한 값을 전달하지 않도록 하기
add
메서드에는 Money
의 amount
가 들어와야한다.
하지만 티켓 갯수와 같은 엉뚱한 값이 들어올 수도 있다.
엉뚱한 값이 전달되지 않도록 하려면, Money
타입만 매개변수로 받을 수 있도록 메서드를 변경해야한다.
자바스크립트에서는 타입이 없기 때문에 instanceOf
를 이용해 구현했다.
class Money {
#amount;
#currency;
constructor(amount, currency) {
this.#validateAmount(amount);
this.#validateCurrency(currency);
this.#amount = amount;
this.#currency = currency;
}
getAmount() {
return this.#amount;
}
add(other) {
if (other instanceof Money) {
const added = this.#amount + other.getAmount();
return new Money(added, this.#currency);
}
throw new Error('금액만 더해주십시오.');
}
#validateAmount(amount) {
if (amount < 0) {
throw new Error('금액은 0 이상의 값을 지정해주세요.');
}
}
#validateCurrency(currency) {
if (currency === null) {
throw new Error('통화 단위를 올바르게 지정해주세요.');
}
}
}