부트캠프/Front

[JavaScript] 디자인 패턴

혀니hyun 2025. 3. 19. 09:39

 

디자인 패턴은 효율적이고 유지보수하기 쉬운 코드 구조를 만들기 위한 일반적인 해결 방법이다.

JavaScript에서는 객체지향 프로그래밍(OOP), 모듈화, 비동기 처리 등을 다루는 여러 패턴이 존재.

 


🎯 1. Singleton Pattern (싱글턴 패턴)

 

 하나의 인스턴스만 생성하고, 어디서든 동일한 인스턴스를 공유하는 패턴.

 전역적으로 공유해야 하는 설정 데이터, 데이터베이스 연결, 상태 관리 등에 많이 사용됨.

 


📌 JavaScript에서 싱글턴 패턴 구현

const Singleton = (function () {
    let instance; // 단 하나의 인스턴스를 저장할 변수

    function createInstance() {
        return { message: "나는 유일한 인스턴스야!" };
    }

    return {
        getInstance: function () {
            if (!instance) {
                instance = createInstance();
            }
            return instance;
        }
    };
})();

const obj1 = Singleton.getInstance();
const obj2 = Singleton.getInstance();

console.log(obj1 === obj2); // true (항상 같은 인스턴스 반환)

 항상 동일한 인스턴스를 반환하므로 불필요한 객체 생성을 방지할 수 있음.

 


🎯 2. Factory Pattern (팩토리 패턴)

 

 객체를 직접 생성하는 대신, 객체 생성을 담당하는 “팩토리 함수”를 통해 객체를 반환하는 패턴.

 객체의 생성 과정을 캡슐화하여, 유연한 코드 작성이 가능.

 


📌 JavaScript에서 팩토리 패턴 구현

function UserFactory(name, role) {
    return {
        name,
        role,
        introduce() {
            console.log(`안녕하세요, 저는 ${this.name}이고, 역할은 ${this.role}입니다.`);
        }
    };
}

const admin = UserFactory("Alice", "관리자");
const guest = UserFactory("Bob", "손님");

admin.introduce(); // 안녕하세요, 저는 Alice이고, 역할은 관리자입니다.
guest.introduce(); // 안녕하세요, 저는 Bob이고, 역할은 손님입니다.

 객체를 생성하는 방식을 감추고, 필요할 때마다 원하는 객체를 쉽게 만들 수 있음.

 


🎯 3. Mediator Pattern (중재자 패턴)

 

 객체 간의 직접적인 의존성을 제거하고, “중재자(Mediator)“를 통해 간접적으로 통신하도록 만드는 패턴.

 복잡한 컴포넌트 간의 의존성을 줄이고 유지보수를 쉽게 할 수 있음.

 


📌 JavaScript에서 미디에이터 패턴 구현

class Mediator {
    constructor() {
        this.participants = [];
    }

    register(participant) {
        this.participants.push(participant);
        participant.setMediator(this);
    }

    send(message, sender) {
        this.participants.forEach(participant => {
            if (participant !== sender) {
                participant.receive(message);
            }
        });
    }
}

class Participant {
    constructor(name) {
        this.name = name;
        this.mediator = null;
    }

    setMediator(mediator) {
        this.mediator = mediator;
    }

    send(message) {
        console.log(`${this.name}가 메시지를 보냄: ${message}`);
        this.mediator.send(message, this);
    }

    receive(message) {
        console.log(`${this.name}가 메시지를 받음: ${message}`);
    }
}

const mediator = new Mediator();
const user1 = new Participant("User1");
const user2 = new Participant("User2");

mediator.register(user1);
mediator.register(user2);

user1.send("안녕하세요!");
// User1이 메시지를 보냄: 안녕하세요!
// User2가 메시지를 받음: 안녕하세요!

 객체들 간의 직접적인 통신을 피하고, 중앙 관리자(Mediator)가 제어하도록 함.

 


🎯 4. Observer Pattern (옵저버 패턴)

 

 한 객체의 상태 변화가 발생하면, 이를 자동으로 감지하고 등록된 다른 객체들(옵저버)에게 알리는 패턴.

 이벤트 기반 시스템, 리액티브 프로그래밍, Pub-Sub(발행-구독) 모델에서 많이 사용됨.

 


📌 JavaScript에서 옵저버 패턴 구현

class Subject {
    constructor() {
        this.observers = [];
    }

    subscribe(observer) {
        this.observers.push(observer);
    }

    unsubscribe(observer) {
        this.observers = this.observers.filter(obs => obs !== observer);
    }

    notify(data) {
        this.observers.forEach(observer => observer.update(data));
    }
}

class Observer {
    constructor(name) {
        this.name = name;
    }

    update(data) {
        console.log(`${this.name}가 업데이트를 받음: ${data}`);
    }
}

const subject = new Subject();
const observer1 = new Observer("Observer 1");
const observer2 = new Observer("Observer 2");

subject.subscribe(observer1);
subject.subscribe(observer2);

subject.notify("새로운 데이터 도착!");  
// Observer 1가 업데이트를 받음: 새로운 데이터 도착!
// Observer 2가 업데이트를 받음: 새로운 데이터 도착!

 한 객체(Subject)의 변경 사항이 여러 옵저버들에게 자동으로 반영됨

 


🎯 5. Module Pattern (모듈 패턴)

 

 코드를 모듈화하여 변수, 함수 등을 “외부에서 직접 접근하지 못하도록 보호”하는 패턴.

 클로저(Closure) 를 활용하여 정보 은닉(Encapsulation) 을 구현함.

 


📌 JavaScript에서 모듈 패턴 구현 (IIFE 사용)

const CounterModule = (function () {
    let count = 0; // private 변수

    return {
        increment() {
            count++;
            console.log(`Count: ${count}`);
        },
        decrement() {
            count--;
            console.log(`Count: ${count}`);
        },
        getCount() {
            return count;
        }
    };
})();

CounterModule.increment(); // Count: 1
CounterModule.increment(); // Count: 2
console.log(CounterModule.getCount()); // 2

 모듈 패턴을 사용하면 외부에서 count 변수에 직접 접근할 수 없음!

 


🎯 정리

 

 싱글턴 패턴 → 단 하나의 인스턴스만 생성하여 공유

 팩토리 패턴 → 객체 생성을 캡슐화하여 유연성 증가

 미디에이터 패턴 → 객체 간의 직접적인 의존성을 줄이고 중앙 관리자(Mediator)가 통신 담당

 옵저버 패턴 → 한 객체의 변화가 여러 옵저버에게 자동으로 반영

 모듈 패턴 → 클로저를 활용하여 정보 은닉 및 코드 모듈화

 

코드의 유지보수성 향상 & 구조적인 설계를 위해 적절한 패턴을 선택하여 사용함.