우테코 프리코스를 진행 중 코드리뷰를 해드리면서 static 메서드와 인스턴스 메서드 중 어느 것이 적합한지에 대해 고민하게 되어 이를 정리해 보았다.
의문을 가지게 된 코드는 다음과 같은데,
// static 메서드로 클래스를 생성하지 않고 메서드를 호출
class InputManager {
staic getCarName() { ... }
}
class App {
constructor() {}
async run () {
const userInput = await InputManager.getCarName()
}
}
// ------------------------------------------
// 인스턴스를 생성하여 사용하는 방식
class InputManager {
getCarName() { ... }
}
class App {
#inputManager;
constructor() {
this.#inputManager = new InputManager()
}
async run () {
const userInput = await this.#inputManager.getCarName()
}
}
사용자 입력을 담당하는 InputManager 클래스의 getCarName이 각각 static일 때와 아닐 때의 코드이다.
나는 첫번째 케이스 처럼 static으로 관리를 했었다.
나름 static으로 지정한 이유는 메소드를 활용할 때 instancte 내에 어떤 필드의 값을 활용해서 실행하는 함수가 아니기 때문이었고, 일반 함수가 아니라 클래스의 static 메소드로 선언한 이유는 InputManager가 수행하는 여러 입력 관련 로직을 하나로 관리하기 위해서이다.
그렇다면 또 관련한 부분만 파일로 관리하지 않은 이유는 이번 과제에 한해서 InputManager
와 관련있는 로직이다. 즉, 출처를 정확하게 알 수 있는 장점이 있을 것 같아 이런 식으로 작성했다.
두번째 케이스는 다른 분의 코드를 참조한 것인데, App의 생성자에서 InputManager 인스턴스를 생성하여 이후 로직에 활용하는 것으로 보였다.
→ 따라서 사용자 입력을 받는 단순 함수는 굳이 인스턴스 생성을 필요로 하지 않으므로, static 메서드로 구현하는 것이 메모리와 관리 측면에서 이점이 있다는 것을 알게 되었다.
일반적으로 클래스에서 static을 활용하는 건 클래스 자체에서 직접 상태에 접근하거나 공유 가능한 메소드를 만들기 위해서이다. static을 다음과 같은 상황에서 활용할 수 있다.
공유된 기능 제공
인스턴스 없이 사용 가능
앞서 살펴봤듯 별도의 인스턴스 생성 필요없이 함수를 실행할수 있다. 인스턴스를 생성하지 않기 떄문에 메모리 사용량을 줄일 수 있고, 반복적으로 인스턴스 생성이 불필요할 때 활용하기 좋다고 한다.
불변 상수 정의
static을 통해서 클래스 내부에 통용될 수 있는 상수를 정의할 수 있다고 있다. 매번 인스턴스 마다 상수를 만들 필요가 없다.
? 외부에서 상수를 주입하는 것과 클래스 내부에서 상수를 관리하는 것은 어떤 차이가 있을까 ?
외부에서 상수를 주입하는 경우
// constants.js
export const MAX_CONNECTIONS = 5;
// 사용 시
import { MAX_CONNECTIONS } from './constants.js';
console.log(MAX_CONNECTIONS); // 5
내부에서 상수를 관리하는 경우
class Config {
static MAX_CONNECTIONS = 5;
}
console.log(Config.MAX_CONNECTIONS); // 5
클래스 내부에서 관리하게 되면 클래스와 관련된 정보가 하나의 구조 안에 존재한다는 점에서 응집도가 높아진다.
반면에 외부에서 상수를 관리하게 되면 명시적으로 Import 해줘야하고, 해당 상수의 의미를 파악하기 위해 각 상수들의 이름이나 😂 보다 명확하게 작성해야 한다. 상수가 많아질 수록 네임스페이스가 분리되지 않아서 충돌 가능성이 높아지게 된다.
그래서 클래스와 연관성이 높고 외부에서 사용하지 않는 상수는 클래스 내부에서 static으로 관리하는 것이 더 깔끔한 방법이다.