[JavaScript] 디자인 패턴
디자인 패턴은 효율적이고 유지보수하기 쉬운 코드 구조를 만들기 위한 일반적인 해결 방법이다.
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)가 통신 담당
✔ 옵저버 패턴 → 한 객체의 변화가 여러 옵저버에게 자동으로 반영
✔ 모듈 패턴 → 클로저를 활용하여 정보 은닉 및 코드 모듈화
코드의 유지보수성 향상 & 구조적인 설계를 위해 적절한 패턴을 선택하여 사용함.