본문 바로가기
Personal-Study/Design Patterns

[TS Design Patterns] 구조 패턴 - 브리지

by Aaron-Kim 2023. 10. 23.

Bridge

- 큰 클래스 또는 밀접하게 관련된 클래스들의 집합을 두 개의 개별 계층 구조 (추상화 및 구현)로 나눈 후

   각각 독립적으로 개발할 수 있도록 함

- 상속에서 객체 합성으로 전환

- 한 클래스 내에서 모든 상태와 행동들을 갖는 대신 새 계층 구조의 객체를 참조하도록 함

- 추상화 (인터페이스)

  - 일부 객체에 대한 상위 수준의 제어 레이어

  - 제어 레이어는 실제 작업을 수행해서는 안되며 구현 레이어 (플랫폼)에 위임해야 함

  - ex) 추상화 - GUI, 구현 - GUI 레이어가 사용자와 상호작용하여 그 결과로 호출하는 배경 운영 체제 코드 (API)

- 구현

- 브리지 패턴은 클래스들을 두 개의 계층 구조로 분리하도록 제안함

- 어떤 기능의 여러 변형을 가진 모놀리식 클래스를 나누고 정돈할 때 사용
   (ex. 클래스가 다양한 DB 서버들과 작동하는 경우)

- 비즈니스 로직 또는 거대한 클래스를 독립적으로 개발할 수 있는 별도의 클래스 계층 구조들로 나눔

 

- 예시

/**
 * The Abstraction defines the interface for the "control" part of the two class
 * hierarchies. It maintains a reference to an object of the Implementation
 * hierarchy and delegates all of the real work to this object.
 */
class Abstraction {
  protected implementation: Implementation;

  constructor(implementation: Implementation) {
    this.implementation = implementation;
  }

  public operation(): string {
    const result = this.implementation.operationImplementation();
    return `Abstraction: Base operation with:\n${result}`;
  }
}

/**
 * You can extend the Abstraction without changing the Implementation classes.
 */
class ExtendedAbstraction extends Abstraction {
  public operation(): string {
    const result = this.implementation.operationImplementation();
    return `ExtendedAbstraction: Extended operation with:\n${result}`;
  }
}

/**
 * The Implementation defines the interface for all implementation classes. It
 * doesn't have to match the Abstraction's interface. In fact, the two
 * interfaces can be entirely different. Typically the Implementation interface
 * provides only primitive operations, while the Abstraction defines higher-
 * level operations based on those primitives.
 */
interface Implementation {
  operationImplementation(): string;
}

/**
 * Each Concrete Implementation corresponds to a specific platform and
 * implements the Implementation interface using that platform's API.
 */
class ConcreteImplementationA implements Implementation {
  public operationImplementation(): string {
    return "ConcreteImplementationA: Here's the result on the platform A.";
  }
}

class ConcreteImplementationB implements Implementation {
  public operationImplementation(): string {
    return "ConcreteImplementationB: Here's the result on the platform B.";
  }
}

/**
 * Except for the initialization phase, where an Abstraction object gets linked
 * with a specific Implementation object, the client code should only depend on
 * the Abstraction class. This way the client code can support any abstraction-
 * implementation combination.
 */
function clientCode(abstraction: Abstraction) {
  // ..

  console.log(abstraction.operation());

  // ..
}

/**
 * The client code should be able to work with any pre-configured abstraction-
 * implementation combination.
 */
let implementation = new ConcreteImplementationA();
let abstraction = new Abstraction(implementation);
clientCode(abstraction);

console.log('');

implementation = new ConcreteImplementationB();
abstraction = new ExtendedAbstraction(implementation);
clientCode(abstraction);

 

// pagres-org/react-design-pattern
// bridge-sample.tsx

const 테마 = {
  backgroundColor: 'blue',
  color: 'white',
};

type ButtonUIProps = ButtonHTMLAttributes<HTMLButtonElement> & {
  theme?: {
    color: string;
    backgroundColor: string;
  };
};

type LinkProps = ButtonHTMLAttributes<HTMLButtonElement> &
  PropsWithChildren<{
    url: string;
    uiComponent: (props: ButtonUIProps) => ReactNode;
    uiProps: ButtonUIProps;
  }>;


const ButtonUI = ({ theme = 테마, ...props }: ButtonUIProps) => (
  <button
    {...props}
    style={{
      backgroundColor: theme.backgroundColor,
      color: theme.color,
    }}
  />
);

const Link = ({ url, uiComponent, uiProps, children, ...props }: LinkProps) => {
  const bridgeProps = {
    ...props,
    ...uiProps,
    onClick: () => window.open(url, '_blank'),
  };

  return createElement(uiComponent, bridgeProps, children);
};

export const BridgeSample = () => (
  <Link
    url="https://github.com/pagers-org/react-design-pattern"
    uiComponent={ButtonUI}
    uiProps={{ theme: 테마 }}
  >
    See other patterns
  </Link>
);

 

- 활용


[아티클]

[TS 사용 예시]

[Pagers-org/react-design-pattern]

반응형

댓글