Web/JS

[JS] 디자인 패턴(Design Pattern)_공개 모듈 패턴(Revealing Module Pattern)

메바동 2023. 2. 18. 00:30
728x90

"JavaScript Design Pattern" 포스팅은 ChatGPT에게 "Essential design patterns for JavaScript developers to learn"로 질문한 뒤 나온 내용에 대해 정리하는 포스팅입니다.


 

1. 공개 모듈 패턴(Revealing Module Pattern)

공개 모듈 패턴은 모듈 패턴과 유사한 JavaScript의 디자인 패턴이다.

 

공개 모듈 패턴에서는 모듈 패턴과 마찬가지로 모듈의 비공개 멤버와 함수가 즉시 호출 함수 표현식(IIFE, Immediately Invoked Function Expression)을 사용하여 정의된다.

 

공개 모듈 패턴은 비공개 변수와 함수가 있는 모듈로 시작한다. 이러한 변수와 함수는 모듈 외부에서 접근할 수 없다.

모듈은 공개하려는 비공개 함수에 대한 참조가 포함된 객체를 반환한다.

모듈 외부에서는 반환된 함수를 호출할 수 있지만, 비공개 변수와 기타 함수는 숨겨진 상태로 유지된다.

 

다음은 공개 모듈 패턴의 예이다.

 

const myModule = (function() {
  let privateVar = 'Hello World';

  function privateFunc() {
    console.log(privateVar);
  }

  function publicFunc() {
    privateFunc();
  }

  return {
    publicFunc: publicFunc
  };
})();

 

이 예제에서는 privateVar라는 비공개 변수와 privateFunc라는 비공개 함수가 있는 myModule이라는 모듈이 있다.

privateFunc 함수는 privateVar의 값을 콘솔에 기록한다. 또한 privateFunc를 호출하는 publicFunc라는 공용 함수도 있다.

 

publicFunc를 공용 메서드로 노출하려면 IIFE에서 publicFunc에 대한 참조가 있는 객체를 반환한다.

이 메서드는 모듈 외부에서 접근할 수 있는 유일한 공용 메서드이다.

모듈 외부에서 myModule.publicFunc()를 호출하게 되면, 비공개 privateFunc 메서드가 호출되고, 이 메서드는 privateVar의 값을 콘솔에 기록한다.

 

공개 모듈 패턴의 한 가지 장점은 공개하고 싶은 메서드와 프로퍼티만 노출하고 나머지는 비공개로 유지할 수 있다는 점이다. 이를 통해 전역 변수와 함수의 수를 줄임으로써 보다 모듈화 되고 유지보수가 쉬운 코드를 만들 수 있다.

 

 

 

2. Module Pattern과 Revealing Module Pattern의 차이점

내가 보기에는 모듈 패턴과 공개 모듈 패턴의 차이가 없는 것 같아 여러 번 질문한 뒤 정리가 될 수 있었다.

결국 공개 모듈 패턴은 모듈 패턴의 변형 여러 가지 변형 중 한 가지인 것이다.

 

기본 모듈 패턴이 충족해야 하는 조건은 두 가지이다.

  • 비공개 멤버는 클로저에 존재한다.
  • 공용 멤버는 반환 객체에 노출된다.

이 정의에는 모호한 부분들이 많은데, 이 모호성을 다르게 하여 모듈 패턴의 변형을 만들 수 있다.

 

공개 모듈 패턴은 기본 모듈 패턴의 조건 2가지 외에도 다음과 같은 조건을 충족해야 한다.

  • 모든 멤버가 공개 또는 비공개 여부와 관계없이 클로저에 정의되어 있다.
  • 반환 객체는 함수 정의가 없는 객체 리터럴이다. 객체의 값은 클로저 변수이다.
  • 모든 참조는 반환 객체가 아닌 클로저 변수를 통해 이루어진다.

 

즉, 지난 모듈 패턴의 연습 코드를 푼 방식은 공개 모듈 패턴이라고 할 수 있다. ChatGPT는 모듈 패턴에 맞게 스켈레톤 코드를 주었는데 내가 무시하고 공개 모듈 패턴으로 풀어버린 것이다.

 

ChatGPT에게 모듈 패턴과 공개 모듈 패턴의 차이점을 질문했을 때 다음과 같은 답변을 얻었다.

 

 

 

모듈 패턴은 즉시 호출 함수 표현식(IIFE)을 사용하여 비공개 및 공개 변수와 함수를 생성하는 JavaScript 모듈을 만들기 위한 디자인 패턴이다. 비공개 변수와 함수는 모듈 외부에서 접근할 수 없으며 공개 메서드는 객체로 반환된다. 이 패턴은 캡슐화를 제공하고 비공개 변수와 함수가 전역 범위에서 숨겨지므로 명명 충돌을 방지하는 데 도움이 된다.

 

공개 모듈 패턴은 모듈 패턴의 변형으로, 다른 접근 방식을 사용하여 공용 API를 노출한다. 모든 공용 메서드가 포함된 객체를 반환하는 대신, 공개 모듈 패턴은 노출하려는 비공개 메서드에 대한 참조가 포함된 객체를 반환한다. 이를 통해 비공개 변수와 함수를 숨기면서 공개 API에 대한 접근을 제공할 수 있다.

 

다음은 두 패턴의 몇 가지 다른 차이점이다:

 

  1. 구문(Syntax): 모듈 패턴은 객체 리터럴을 사용하여 공용 메서드를 정의하는 반면, 공개 모듈 패턴은 비공개 메서드를 참조하는 변수로 정의한다.
  2. 비공개 상태(Private State): 모듈 패턴에서 비공개 변수와 함수는 모듈 내에서만 접근할 수 있다. 공개 모듈 패턴에서는 변수와 함수는 여전히 모듈 내에서만 접근할 수 있지만, 공개 API는 비공개 메서드에 대한 참조를 노출한다.
  3. 명명 규칙(Naming Conventions): 모듈 패턴에서 비공개 변수와 함수 앞에는 비공개임을 나타내는 밑줄이 붙는 경우가 많다. 공개 모듈 패턴에서는 비공개 메서드가 직접 노출되지 않으므로 이 규칙이 필요하지 않다.
  4. 객체 리터럴 오버헤드(Object Literal Overhead): 모듈 패턴에서 공개 API는 객체 리터럴로 정의되며, 이는 더 장황하고 읽기 어려울 수 있다. 공개 모듈 패턴에서는 공개 API가 변수로 정의되어 더 간결하고 읽기 쉬울 수 있다.

 

 

 

3. Revealing Module Pattern 연습 코드

ChatGPT에게 "Give me a challenge to practice the Revealing Module Pattern in JavaScript."라고 질문한 뒤 나온 문제와 그에 대한 답이다.

 

 

이를 구현한 코드는 다음과 같다.

 

const inventoryModule = (function() {
  // 비공개 멤버 및 함수
  const products = [];

  function getProductIndexByName(name) {
    for (let i = 0; i < products.length; i++) {
      if (products[i].name === name) {
        return i;
      }
    }
    return -1;
  }

  function calculateInventoryValue() {
    let value = 0;
    for (let i = 0; i < products.length; i++) {
      value += products[i].price * products[i].quantity;
    }
    return value;
  }

  // 공개 함수
  function addProduct(name, price, quantity) {
    const index = getProductIndexByName(name);
    if (index !== -1) {
      products[index].quantity += quantity;
    } else {
      products.push({
        name: name,
        price: price,
        quantity: quantity
      });
    }
  }

  function removeProduct(name) {
    const index = getProductIndexByName(name);
    if (index !== -1) {
      products.splice(index, 1);
    }
  }

  function getProductCount() {
    let count = 0;
    for (let i = 0; i < products.length; i++) {
      count += products[i].quantity;
    }
    return count;
  }

  function getInventoryValue() {
    return calculateInventoryValue();
  }

  // 공용 메서드 반환
  return {
    addProduct,
    removeProduct,
    getProductCount,
    getInventoryValue
  };
})();

// 테스트
inventoryModule.addProduct('Product 1', 10, 5);
inventoryModule.addProduct('Product 2', 20, 3);
console.log(inventoryModule.getProductCount()); // Output: 8
console.log(inventoryModule.getInventoryValue()); // Output: 110
inventoryModule.removeProduct('Product 1');
console.log(inventoryModule.getProductCount()); // Output 3
console.log(inventoryModule.getInventoryValue()); // Output 60

 

이번 연습 코드는 ChatGPT에서 스켈레톤 코드가 아닌 답을 자꾸 생성하여 해당 답을 그대로 가져왔다.

다음부터는 연습과 그에 맞는 스켈레톤 코드를 달라는 질문을 해야될 것 같다.

728x90