프론트엔드/React

리액트 디자인 패턴(팩토리 패턴 - Factory Pattern)

Hyeon_E 2023. 9. 13. 22:53

팩토리 패턴이 나오게 된 계기

객체 지향 디자인 패턴의 기본 원칙은 확장은 열려 있어야 하지만 수정은 닫혀 있어야 한다는 것

코드를 수정하지 않아도 모듈의 기능을 확장하거나 변경할 수 있어야 함

그렇기 때문에 수정이 일어날 가능성이 큰 부분과 그렇지 않은 부분을 분리하는 것이 좋음

 

객체는 속성과 함수가 변경 또는 추가 될 가능성이 높기 때문에 객체의 생성을 담당하는 코드는 변경의 가능성이 높음

따라서 클래스를 한 곳에서 관리하여 결합도를 줄이기 위하여 팩토리 패턴이 나타나게 된 것

결합도(의존성)이란?

결합도는 한 클래스의 변경점이 얼마나 다른 클래스에 영향을 주는가를 의미함

 

팩토리 패턴

부모 클래스에서 객체를 생성할 수 있는 인터페이스를 제공하지만 자식 클래스들이 생성될 객체들의 유형을 변경할수 있도록 하는 생성 패턴

즉 코드에서 생성 부분을 떼어내 추상화한 패턴임 상속관계에 있는 두 클래스에서 상위 클래스가 중요한 뼈대를 결정하고, 하위 클래스에서 객체 생성에 관한 구체적인 내용을 결정함

리액트에서 팩토리 패턴

리액트에서 팩토리 패턴은 객체 생성을 추상화하여 동적으로 객체를 생성하는 방법

컴포넌트를 조건에 따라 동적으로 생성하고 반환하는데 유용함

객체 생성 로직이 복잡성이나 변경가능성이 높거나 다양한 종류의 객체를 생성해야할때, 객체 생성 과정을 캡슐화하여 중복 코드를 줄이고자 하는 상황에서 사용됨

 

팩토리얼 패턴 사용예시

1. 팩토리 함수 생성과 내부 로직

여러 종류의 컴포넌트를 생성하기 위한 팩토리 함수를 만듬

이 함수는 컴포넌트 종류를 식별하는 인자한 필요한 속성을 받음

함수 내부에서 'type' 인자를 기반으로 어떤 종류의 컴포넌트를 생성할지 결정함

const InputForm = ({ config }) => {
  const getElement = ({
    type,
    label,
    errorFlag,
    errorMsg,
    options,
    onChange,
    value,
  }) => {
    switch (type) {
      case "text":
        return (
          <div>
            <label>{label}</label>
            <input type="text" onChange={onChange} value={value} />
            {errorFlag && <span>{errorMsg}</span>}
          </div>
        );
      case "number":
        return (
          <div>
            <label>{label}</label>
            <input type="number" onChange={onChange} value={value} />
            {errorFlag && <span>{errorMsg}</span>}
          </div>
        );
      case "password":
        return (
          <div>
            <label>{label}</label>
            <input type="password" onChange={onChange} value={value} />
            {errorFlag && <span>{errorMsg}</span>}
          </div>
        );
      case "date":
        return (
          <div>
            <label>{label}</label>
            <input type="date" onChange={onChange} value={value} />
            {errorFlag && <span>{errorMsg}</span>}
          </div>
        );
      case "dropdown":
        return (
          <div>
            <label>{label}</label>
            <select onChange={onChange} value={value}>
              {options.map((option) => {
                return <option value={option}>{option}</option>;
              })}
            </select>
            {errorFlag && <span>{errorMsg}</span>}
          </div>
        );
      default:
        return <div>잘못된 type</div>;
    }
  };
  return (
    <div>
      {config.map((element, index) => {
        return <div key={index}>{getElement(element)}</div>;
      })}
    </div>
  );
};

export default InputForm;

 

2. 팩토리 함수 사용

팩토리 함수를 사용하여 컴포넌트를 생성하고 필요한 속성을 전달하여 컴포넌트를 렌더링함

return (
    <>
      <h1>Login</h1>
      <InputForm config={getLoginConfig(onChange, formDetails)} />
   	</>
)

...

const getLoginConfig = (onChange, formDetails) => {
  return [
    {
      label: "Email",
      type: "text",
      onChange: (e) => onChange(e.target.value, "email"),
      value: formDetails.email,
    },
    {
      label: "Password",
      type: "password",
      onChange: (e) => onChange(e.target.value, "password"),
      value: formDetails.password,
    },
  ];
};

 

장점

  • 객체 생성 로직의 캡슐화
    • 팩토리 함수는 객체를 생성하고 필요한 초기 설정을 수행하는 데 필요한 모든 로직을 캡슐화 함 그로인해 객체 생성 로직을 한 곳에 집중할 수 있음
  • 확장성 및 유지보수성 증가
    • 객체 생성 로직이 분리되어 수정 시 한곳만 수정할 수 있음
  • 중복 코드 제거
    • 동일한 객체를 여러 번 생성해야 하는 경우, 팩토리 패턴을 사용하여 중복 코드를 방지할 수 있음

팩토리 패턴을 사용하면 객체 생성 프로세스를 캡슐화함으로써 애플리케이션의 구성요소, 모의 데이터, 구성 객체 또는 기타 요소 인스턴스 생성에 대한 일관된 접근 방식을 촉진함

React 애플리케이션에서 팩토리 패턴을 사용하면 코드 구성 개선, 모듈성 향상, 재사용성 향상 등 여러가지 이점을 얻을 수 있음