GoF: 팩토리 메서드
로키2026.02.13
loading ...
// 공통 로직을 안에 숨긴 함수 팩토리const makeToastHook = (type: "success" | "error") => {return () => {const showToast = (msg: string) => {// type에 따라 색, 아이콘, 위치 등 결정// ...console.log(`[${type.toUpperCase()}] ${msg}`);};return { showToast };};};// 클라이언트 코드// success나 error만 넘겨주고, 내부 처리방식은 몰라도 됨const useSuccessToast = makeToastHook("success");const useErrorToast = makeToastHook("error");
// 팩토리 역할: 안전한 useContext 훅을 만들어줌const makeSafeUseContext = <T,>(Context: Context<T | null>, name: string) => {return () => {
장점
단점
나만의 사용 방식
const makeSafeUseContext = <T,>(Context: React.Context<T |
결과
트레이드오프
과하게 쓰면 관리가 복잡해지고 불편해진다거나, 초기 학습 비용이 든다고 하는데,
개인적으로는 그 지점까지 가면 설계가 잘못된 것이라 생각하긴 함.
실제로 저도 과한 추상화 때문에 고생한 적이 있었는데,
그때 설계를 다시 해서 모듈을 적절히 분리하고 나니,
각 모듈이 담당하는 책임이 줄어들면서 하나의 모듈에 너무 많은 내용을 몰아 넣지 않게 됐어요.
적절히만 쓰면 유지 보수 측면에서 훨씬 유리하다고 생각합니다.
로깅처럼 공통 기능을 잘 추상화해두면, 이후에는 수정 없이 재사용만 하면서도 일관된 형태로 활용할 수 있어서 유용한 것 같습니다!
type HttpClient = {get: <T>(url: string) => Promise<T>;post: <T>(url: string, body: unknown) => Promise<T>;};const makeHttpClient = (baseUrl: string, withAuth: boolean): HttpClient => {const commonHeaders: HeadersInit = {"Content-Type": "application/json",};return {async get<T>(url: string) {const res = await fetch(baseUrl + url, {method: "GET",headers: {...commonHeaders,...(withAuth && { Authorization: "Bearer token" }),},});return res.json() as Promise<T>;},async post<T>(url: string, body: unknown) {const res = await fetch(baseUrl + url, {method: "POST",headers: {...commonHeaders,...(withAuth && { Authorization: "Bearer token" }),},body: JSON.stringify(body),});return res.json() as Promise<T>;},};};// 사용 예시export const publicApi = makeHttpClient("https://api.example.com", false);export const authedApi = makeHttpClient("https://api.example.com", true);