icon안동민 개발노트

디자인 패턴 in 자바스크립트


 디자인 패턴은 소프트웨어 개발에서 자주 발생하는 문제들에 대한 재사용 가능한 해결책입니다.

 이들은 코드의 구조화, 유지보수성 향상, 그리고 개발자 간 의사소통을 facilize하는 데 중요한 역할을 합니다.

 자바스크립트에서도 이러한 패턴들이 널리 사용되며, 언어의 특성에 맞게 적용됩니다.

생성 패턴 (Creational Patterns)

 생성 패턴은 객체 생성 메커니즘을 다룹니다.

 1. 싱글톤 (Singleton)

  • 개념 : 클래스의 인스턴스가 하나만 생성되도록 보장
  • 구현
const Singleton = (function() {
  let instance;
  function createInstance() {
    return new Object("I am the instance");
  }
  return {
    getInstance: function() {
      if (!instance) {
        instance = createInstance();
      }
      return instance;
    }
  };
})();
 
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // true
  • 사용 사례 : 설정 관리, 데이터베이스 연결 등
  • 장점 : 전역 상태 관리 용이
  • 단점 : 단위 테스트 어려움, 과도한 사용 시 결합도 증가

 2. 팩토리 (Factory)

  • 개념 : 객체 생성 로직을 캡슐화
  • 구현
function carFactory(type) {
  return {
    type: type,
    drive: function() { console.log(`Driving a ${this.type}`); }
  }
}
 
const sedan = carFactory("sedan");
sedan.drive(); // "Driving a sedan"
  • 사용 사례 : 다양한 유형의 객체 생성
  • 장점 : 객체 생성의 유연성 제공
  • 단점 : 많은 클래스 생성 시 복잡해질 수 있음

구조 패턴 (Structural Patterns)

 구조 패턴은 객체 구성에 관한 패턴입니다.

 1. 프록시 (Proxy)

  • 개념 : 다른 객체에 대한 대리자 또는 placeholder 제공
  • 구현
const target = {
  name: "John",
  age: 35
};
 
const handler = {
  get: function(obj, prop) {
    console.log(`Property ${prop} accessed`);
    return obj[prop];
  }
};
 
const proxy = new Proxy(target, handler);
console.log(proxy.name); // "Property name accessed" "John"
  • 사용 사례 : 접근 제어, 지연 초기화, 로깅
  • 장점 : 원본 객체 보호, 추가 기능 제공
  • 단점 : 복잡성 증가, 약간의 성능 오버헤드

 2. 데코레이터 (Decorator)

  • 개념 : 객체에 동적으로 새로운 책임 추가
  • 구현
function coffee() {
  return {
    cost: function() { return 5; },
    description: function() { return "Simple coffee"; }
  }
}
 
function milk(coffee) {
  const cost = coffee.cost();
  const description = coffee.description();
  coffee.cost = function() { return cost + 2; };
  coffee.description = function() { return description + ", milk"; };
  return coffee;
}
 
let myOrder = coffee();
myOrder = milk(myOrder);
console.log(myOrder.cost()); // 7
console.log(myOrder.description()); // "Simple coffee, milk"
  • 사용 사례 : 기능 확장, UI 컴포넌트 스타일링
  • 장점 : 유연한 기능 확장, 단일 책임 원칙 준수
  • 단점 : 많은 작은 객체 생성 가능성

행동 패턴 (Behavioral Patterns)

 행동 패턴은 객체 간의 알고리즘과 책임 할당을 다룹니다.

 1. 옵저버 (Observer)

  • 개념 : 객체 간 일대다 의존성 정의
  • 구현
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 {
  update(data) {
    console.log("Received update:", data);
  }
}
 
const subject = new Subject();
const observer1 = new Observer();
subject.subscribe(observer1);
subject.notify("Hello observers!");
  • 사용 사례 : 이벤트 핸들링, 상태 변화 감지
  • 장점 : 느슨한 결합, 동적 관계 설정
  • 단점 : 복잡한 업데이트 순서 관리 필요

 2. 모듈 (Module)

  • 개념 : 관련 기능을 캡슐화하고 외부에 인터페이스 제공
  • 구현
    const myModule = (function() {
      let privateVariable = 0;
      function privateMethod() {
        console.log("This is private");
      }
      return {
        publicMethod: function() {
          privateVariable++;
          privateMethod();
        },
        getCount: function() {
          return privateVariable;
        }
      };
    })();
     
    myModule.publicMethod();
    console.log(myModule.getCount()); // 1
  • 사용 사례 : 코드 구조화, 네임스페이스 관리
  • 장점 : 캡슐화, 정보 은닉
  • 단점 : 모든 멤버를 미리 선언해야 함

모던 자바스크립트와 함수형 프로그래밍

 모던 자바스크립트와 함수형 프로그래밍은 일부 전통적인 디자인 패턴의 필요성을 줄였습니다.

 예를 들어,

  • 모듈 패턴은 ES6 모듈 시스템으로 대체될 수 있습니다.
  • 함수형 프로그래밍에서는 고차 함수와 합성을 통해 데코레이터 패턴을 구현할 수 있습니다.
// 함수형 방식의 데코레이터
const withLogging = (fn) => (...args) => {
  console.log('Calling function with args:', args);
  return fn(...args);
};
 
const add = (a, b) => a + b;
const loggedAdd = withLogging(add);
console.log(loggedAdd(2, 3)); // Logs: Calling function with args: [2, 3]  // Returns: 5

프레임워크에서의 디자인 패턴

  • React : 컴포넌트 패턴, 고차 컴포넌트(데코레이터 패턴의 변형)
  • Vue : 옵저버 패턴 (반응형 시스템)
  • Angular : 의존성 주입 패턴

디자인 패턴 학습의 영향

 디자인 패턴을 학습하고 적용하는 것은 다음과 같은 이점을 제공합니다.

  1. 코드 품질 향상 : 검증된 해결책 사용으로 버그 감소
  2. 유지보수성 증가 : 표준화된 구조로 코드 이해와 수정 용이
  3. 개발자 역량 강화 : 문제 해결 능력과 설계 기술 향상
  4. 효율적인 의사소통 : 개발자 간 공통 언어 제공
  5. 확장성 있는 설계 : 미래의 요구사항 변화에 대응 용이

 그러나 패턴의 과도한 사용이나 부적절한 적용은 오히려 코드를 복잡하게 만들 수 있으므로, 상황에 맞는 적절한 사용이 중요합니다.

 디자인 패턴은 소프트웨어 개발의 복잡성을 관리하는 강력한 도구입니다. 자바스크립트에서 이러한 패턴들을 이해하고 적절히 활용함으로써, 개발자는 더 견고하고 유지보수가 용이한 코드를 작성할 수 있습니다. 또한, 패턴에 대한 지식은 기존 라이브러리와 프레임워크의 구조를 이해하는 데도 도움이 됩니다.

 그러나 디자인 패턴은 만능 해결책이 아니며, 각 상황에 맞게 신중히 적용해야 합니다. 때로는 단순한 해결책이 복잡한 패턴보다 더 효과적일 수 있습니다. 따라서 문제의 본질을 정확히 이해하고, 적절한 패턴을 선택하는 능력이 중요합니다.

 결론적으로, 디자인 패턴의 학습과 적용은 자바스크립트 개발자의 기술적 성장과 프로젝트의 성공에 크게 기여할 수 있습니다. 이는 단순히 코드 작성 기술을 넘어, 소프트웨어 아키텍처와 설계에 대한 깊이 있는 이해를 제공함으로써, 더 나은 개발자와 더 나은 소프트웨어를 만드는 데 기여합니다.