[Design Pattern] Compound Pattern에 대해 알아보자.

개잼·2025년 1월 8일
0
post-thumbnail

1. 인사

안녕하세요. 이번에는 Design Pattern에서 Compound Pattern에 대해 알아보려고 합니다.


2. 소개배경

회사에서 꽤 규모가 있는 프로젝트를 진행하던 중, 제가 알던 방식으로는 현재 규모의 프로젝트를 감당하기는 약간 버거웠습니다.

이에 따라 이를 개선할 방법을 찾게 되었고, 그러다보니 여러 디자인패턴에 관심을 가지게 되었습니다. 그래서 이 중 하나인 Compound Pattern에 대해 소개를 해볼까 합니다.


3. Compound Pattern ??

하나의 완결된 UI 컴포넌트를 위해서 작게 세분화된 하위 컴포넌트(Sub Component)가 존재하고,
그 하위 컴포넌트(Sub Component)들을 조합하여 사용하는 디자인 패턴입니다.


4. Compound Pattern 적용 예시-1

  • index.ts
export const A_sectionInfoDetailArea = Object.assign(SectionInfoDetailMain, {
  Header: SectionInfoDetailTitle,
  ExtraInfo,
  table: TableMain,
  tableCaption: TableCaption,
  tableHeader: TableHeader,
  tableBody: TableBody,
});

먼저 index.ts에 A_sectionInfoDetailArea를 정의하였습니다.

이는 메인 컴포넌트, 서브 컴포넌트가 어떤 것인지 명시적으로 정의하기 위하여 index.ts를 다음과 같이 만들었습니다.

해당 코드에서 SectionInfoDetailMain가 Main이 되고, 나머지가 Sub Component가 됩니다.


  • SectionmInfoDetailMain.tsx (Main)
import cn from "classnames";

interface SectionInfoDetailMainProps {
  children: React.ReactNode;
  className?: string;
}

export default function SectionInfoDetailMain({
  children,
  className,
}: SectionInfoDetailMainProps) {
  return <div className={cn(className)}>{children}</div>;
}

이는 Main Component입니다.
classnames와 children을 통해 재사용 및 유연성을 고려하여 코드를 구현하였습니다.


  • SectionInfoDetailTitle.tsx (Sub)
interface SectionInfoDetailTitleProps {
  title?: string;
  children?: React.ReactNode;
}

export default function SectionInfoDetailTitle({
  title,
  children,
}: SectionInfoDetailTitleProps) {
  if (!title) return;

  return (
    <div className="flex">
      <div className="flex w-[140px] ml-4 justify-center px-4 py-2 shadow-md border border-gray-200 rounded-t-lg">
        {title}
      </div>
      {children}
    </div>
  );
}

이는 SectionInfoDetailTitle라는 Sub Component입니다. Main에 종속되어 사용되는 Sub Component입니다. 여기서도 children을 받아서 더 확장할 수 있도록 만들었습니다.


5. Compound Pattern 적용 예시-2

이제는 위의 Main Component, Sub Component를 가지고 어떤식으로 조합하길래 레고라는 표현을 하는지 살펴보도록 하겠습니다.


  • A_sectionInfoArea.tsx
    <A_sectionInfoDetailArea className={classNames}>
      <A_sectionInfoDetailArea.Header title={title}>
        <A_sectionInfoDetailArea.ExtraInfo
          content={content}
          extraInfovalue={extraInfovalue}
        />
      </A_sectionInfoDetailArea.Header>
      <A_sectionInfoDetailArea.table>
        <A_sectionInfoDetailArea.tableHeader fieldData={sectionInfoFieldData} />
        <A_sectionInfoDetailArea.tableBody>
          {genBody()}
        </A_sectionInfoDetailArea.tableBody>
      </A_sectionInfoDetailArea.table>
    </A_sectionInfoDetailArea>

이런식으로 저는 Main과 Header, ExtraInfo, table, tableHeader, tableBody인 Sub Component들로 A_sectionInfoArea를 구현하였습니다.


  • A_sectionInfoArea-2
 <A_sectionInfoDetailArea className={classNames}>
      <A_sectionInfoDetailArea.Header title={title}/>
      <A_sectionInfoDetailArea.table>
        <A_sectionInfoDetailArea.tableHeader fieldData={sectionInfoFieldData} />
        <A_sectionInfoDetailArea.tableBody>
          {genBody()}
        </A_sectionInfoDetailArea.tableBody>
      </A_sectionInfoDetailArea.table>
    </A_sectionInfoDetailArea>

가령 A_sectionInfoArea-2에는 ExtraInfo가 필요 없다고 하면, 해당 Sub Component는 A_sectionInfoArea-2에 추가하지 않는 식으로 구현할 수 있습니다.

이는 마치 내가 만들고자 하는 것에 특정 레고가 필요하냐 필요하지 않느냐에 따라 그것을 가져오냐, 가져오지 않느냐를 판단하듯이 코드를 짤 수 있기에 레고와 같다고 생각했습니다.


6. Compound Pattern 장점

저는 Compound Pattern의 장점은 유연성과 재사용성에 있다고 생각합니다.
코드 예시를 보면, 어떤식으로 제가 유연성과 재사용성을 챙기는지 보실 수 있을거라 생각이 듭니다.

추가로 유연성과 재사용성 이외의 장점이 있는데요, 이는 제가 가장 중요하게 생각하는 Compound Pattern의 장점입니다.

그것은 단일책임원칙을 수행하기 적절하다는 것입니다.

tableHeader는 말 그대로 tableHeader를,
tableBody는 말 그대로 tableBody의 역할을 수행하듯이
Compound Pattern을 적절히 잘 사용하면, 단일책임원칙이 자연스럽게 따라오는 것이 저에게 가장 매력적으로 다가왔던 것 같습니다.

감사합니다.

profile
천천히 나아가는 중

0개의 댓글

관련 채용 정보