[design-patterns] 프록시, 데코레이터, 어댑터 및 브리지 패턴은 어떻게 다릅니 까?

프록시 패턴을보고 있었고 데코레이터, 어댑터 및 브리지 패턴과 같은 끔찍한 것 같습니다. 내가 뭔가를 오해하고 있습니까? 차이점이 뭐야? 프록시 패턴을 사용하는 이유는 무엇입니까? 실제 프로젝트에서 과거에 어떻게 사용 했습니까?



답변

프록시, 데코레이터, 어댑터 및 브리지는 모두 클래스 “래핑”의 변형입니다. 그러나 그들의 용도는 다릅니다.

  • 프록시 는 개체를 지연 인스턴스화하거나 원격 서비스를 호출한다는 사실을 숨기거나 개체에 대한 액세스를 제어하려는 경우에 사용할 수 있습니다.

  • 데코레이터 는 “스마트 프록시”라고도합니다. 이것은 객체에 기능을 추가하려고 할 때 사용되지만 해당 객체의 유형을 확장하지는 않습니다. 이를 통해 런타임에 그렇게 할 수 있습니다.

  • 어댑터 는 추상 인터페이스가 있고 해당 인터페이스를 기능적인 역할은 비슷하지만 다른 인터페이스를 가진 다른 객체에 매핑하려고 할 때 사용됩니다.

  • Bridge 는 Adapter와 매우 유사하지만 추상 인터페이스와 기본 구현을 모두 정의 할 때 Bridge라고합니다. 즉, 일부 레거시 또는 타사 코드에 적응하지 않고 모든 코드의 설계자이지만 다른 구현을 바꿀 수 있어야합니다.

  • Facade 는 하나 이상의 클래스 서브 시스템에 대한 상위 레벨 (읽기 : 단순) 인터페이스입니다. 표현하기 위해 여러 객체가 필요한 복잡한 개념이 있다고 가정합니다. 호출해야하는 메소드가있는 오브젝트를 항상 알 수 없기 때문에 해당 오브젝트 세트를 변경하는 것은 혼란 스럽습니다. 이제 객체 컬렉션에 대해 수행 할 수있는 모든 복잡한 작업에 대해 높은 수준의 방법을 제공하는 Facade를 작성해야합니다. 예 : 같은 방법으로 학교 섹션에 대한 도메인 모델, countStudents(), reportAttendance(), assignSubstituteTeacher(), 등.


답변

Bill의 답변에서 알 수 있듯이 사용 사례는 다릅니다 .

그들의 구조도 마찬가지입니다.

  • 프록시데코레이터는 모두 래핑 된 유형과 동일한 인터페이스를 갖지만 프록시는 인스턴스를 생성하는 반면 데코레이터는 생성자에서 인스턴스를 생성합니다.

  • AdapterFacade는 모두 랩과 인터페이스가 다릅니다. 그러나 어댑터는 기존 인터페이스에서 파생되지만 파사드는 새 인터페이스를 만듭니다.

  • 브리지어댑터는 모두 기존 유형을 가리 킵니다. 그러나 브릿지는 추상 유형을 가리키고 어댑터는 콘크리트 유형을 가리킬 수 있습니다. 브리지를 사용하면 런타임에 구현을 쌍으로 연결할 수 있지만 어댑터는 일반적으로 그렇지 않습니다.


답변

주제에 대한 나의 견해.

네 가지 패턴 모두 공통점이 많으며, 네 가지 패턴 모두 비공식적으로 래퍼 또는 래퍼 패턴이라고도합니다. 모든 구성을 사용하고 주제를 래핑하고 어느 시점에서 주제에 실행을 위임하면 한 메소드 호출을 다른 메소드 호출에 맵핑합니다. 그들은 고객에게 다른 객체를 구성하고 모든 관련 데이터를 복사해야 할 필요성을 아끼지 않습니다. 현명하게 사용하면 메모리와 프로세서가 절약됩니다.

느슨한 결합을 촉진함으로써 안정적인 코드가 불가피한 변경에 덜 노출되고 동료 개발자가 더 잘 읽을 수있게됩니다.

어댑터

어댑터는 주제 (어댑터)를 다른 인터페이스에 적응시킵니다. 이런 식으로 명목상 다른 유형의 컬렉션에 객체를 추가 할 수 있습니다.

어댑터는 관련 메소드 만 클라이언트에 노출하고 다른 모든 메소드를 제한하여 외부 라이브러리 적응과 같은 특정 컨텍스트에 대한 사용 의도를 공개하여 애플리케이션 요구에 덜 일반적이며 집중적으로 보이도록합니다. 어댑터는 코드의 가독성과 자기 설명을 향상시킵니다.

어댑터는 한 팀을 다른 팀의 휘발성 코드로부터 보호합니다. 해외 팀을 다룰 때 구세주 도구 😉

덜 언급 된 목적은 주제 클래스가 주석을 초과하지 않도록하는 것입니다. 주석을 기반으로하는 많은 프레임 워크에서 이것은 그 어느 때보 다 중요한 사용법이되었습니다.

어댑터는 단일 상속에 대한 Java 제한 사항을 극복하는 데 도움이됩니다. 하나의 엔벨로프에 여러 명의 적응자를 결합하여 여러 상속을 감수 할 수 있습니다.

코드 측면에서 어댑터는 “얇다”. 단순히 적응자 메소드를 호출하고 그러한 호출을하기 위해 필요한 데이터 변환을하는 것 외에, 적응자 클래스에 많은 코드를 추가해서는 안됩니다.

JDK 또는 기본 라이브러리에는 좋은 어댑터 예제가 없습니다. 응용 프로그램 개발자는 라이브러리를 응용 프로그램 특정 인터페이스에 맞추기 위해 어댑터를 작성합니다.

데코레이터

데코레이터는 하나의 메소드를 다른 메소드에 맵핑 할뿐만 아니라 더 많은 것을 수행하고 일부 주제 메소드의 동작을 수정하며 주제 메소드를 전혀 호출하지 않고 다른 오브젝트, 헬퍼 오브젝트에 위임하지 않기로 결정할 수 있습니다.

데코레이터는 일반적으로 주제에 대한 로깅, 암호화, 형식 지정 또는 압축과 같은 래핑 된 객체에 (투명하게) 기능을 추가합니다. 이 새로운 기능은 많은 새로운 코드를 가져올 수 있습니다. 따라서 데코레이터는 일반적으로 어댑터보다 훨씬 “더 빠르다”.

데코레이터는 주제 인터페이스의 하위 클래스 여야합니다. 피사체 대신 투명하게 사용할 수 있습니다. BufferedOutputStream을 참조하십시오. 여전히 OutputStream이며 그대로 사용할 수 있습니다. 이는 어댑터와의 주요 기술적 차이점입니다.

전체 데코레이터 제품군의 교재 예제는 JDK (Java IO)에 있습니다. BufferedOutputStream , FilterOutputStreamObjectOutputStream 과 같은 모든 클래스 는 OutputStream의 데코레이터입니다 . 그들은 하나의 데코레이터가 다시 장식되어 더 많은 기능을 추가하는 양파 층이 될 수 있습니다.

대리

프록시는 일반적인 래퍼가 아닙니다. 프록시 주제 인 랩핑 된 오브젝트는 프록시 작성시 아직 존재하지 않을 수 있습니다. 프록시는 종종 내부적으로 만듭니다. 요청시 생성 된 무거운 객체이거나 다른 JVM 또는 다른 네트워크 노드의 원격 객체 일 수도 있고 원시 코드의 구성 요소 인 Java 이외의 객체 일 수도 있습니다. 랩핑하거나 다른 오브젝트에 위임 할 필요가 없습니다.

가장 일반적인 예는 원격 프록시, 무거운 객체 이니셜 라이저 및 액세스 프록시입니다.

  • 원격 프록시 – 주제는 원격 서버, 다른 JVM 또는 Java 이외의 시스템에 있습니다. 프록시는 메소드 호출을 RMI / REST / SOAP 호출 또는 필요한 모든 것으로 변환하여 클라이언트를 기본 기술에 노출시키지 않도록 보호합니다.

  • 지연로드 프록시 – 첫 번째 사용 또는 첫 번째 집중 사용으로 만 오브젝트를 완전히 초기화하십시오.

  • 액세스 프록시 – 주제에 대한 액세스를 제어합니다.

정면

Facade는 Least Knowledge (Law of Demeter)의 디자인 원칙과 밀접한 관련이 있습니다. 외관은 어댑터와 매우 유사합니다. 둘 다 감싸고 둘 다 한 객체를 다른 객체에 매핑하지만 의도가 다릅니다. Facade는 피사체의 복잡한 구조, 복잡한 객체 그래프를 평탄화하여 복잡한 구조에 대한 액세스를 단순화합니다.

Facade는 복잡한 구조를 감싸서 평평한 인터페이스를 제공합니다. 이것은 대상 구조에서 클라이언트 객체가 내부 관계에 노출되는 것을 방지하여 느슨한 결합을 촉진합니다.

다리

구현뿐만 아니라 추상화가 다양한 어댑터 패턴의 더 복잡한 변형. 위임에 하나 이상의 간접 참조를 추가합니다. 추가 위임은 다리입니다. 적응 형 인터페이스에서도 어댑터를 분리합니다. 다른 랩핑 패턴보다 복잡성이 증가하므로주의해서 적용하십시오.

생성자의 차이점

생성자를 볼 때 패턴 차이도 분명합니다.

  • 프록시 가 기존 객체를 래핑하지 않습니다. 생성자에는 제목이 없습니다.

  • 데코레이터어댑터 는 기존 객체를 래핑하며 일반적으로
    생성자에서 제공됩니다.

  • Facade 생성자는 전체 객체 그래프의 루트 요소를 사용합니다. 그렇지 않으면 Adapter와 같습니다.

실제 예 – JAXB Marshalling Adapter . 이 어댑터의 목적은 간단한 플랫 클래스를 외부에서 요구되는보다 복잡한 구조에 매핑하고 과도한 주석으로 주제 클래스를 “오염”시키는 것을 방지하는 것입니다.


답변

많은 GoF 패턴에는 많은 중복이 있습니다. 그것들은 모두 다형성의 힘을 기반으로하며 때로는 의도 만 다를뿐입니다. (전략 대 상태)

Head First Design Patterns를 읽은 후 패턴에 대한 나의 이해가 100 배 증가했습니다 .

나는 그것을 강력히 추천합니다!


답변

전문가의 모든 좋은 답변은 이미 각 패턴의 의미를 설명했습니다.

요점 을 장식 하겠습니다 .

데코레이터 :

  1. 런타임에 객체에 동작 추가 . 상속은이 기능을 달성하는 열쇠이며,이 패턴의 장단점입니다.
  2. 인터페이스 의 동작 을 수정합니다 .

(체인)와 예 : java.io관련된 패키지 클래스 InputStreamOutputStream인터페이스

FileOutputStream fos1 = new FileOutputStream("data1.txt");
ObjectOutputStream out1 = new ObjectOutputStream(fos1);

대리:

  1. 객체를 캐싱하고 클라이언트 / 호출자에 대한 액세스를 제어하여 지연 초기화, 성능 개선에 사용 . 대체 동작을 제공하거나 실제 객체를 호출 할 수 있습니다. 이 과정에서 새로운 객체가 생성 될 수 있습니다.
  2. 객체 연결을 허용하는 Decorator 와 달리 프록시 는 연결을 허용하지 않습니다.

예 : java.rmi패키지 클래스.

어댑터:

  1. 두 개의 관련되지 않은 인터페이스가 다른 객체를 통해 함께 작동 할 수 있습니다. 동일한 역할을 할 수 있습니다.
  2. 원래 인터페이스를 수정합니다 .

예를 들어, java.io.InputStreamReader( InputStream반환 Reader)

다리:

  1. 추상화와 구현 모두 독립적으로 변할 수있다 .
  2. 상속보다 구성을 사용합니다 .

예를 들어, 컬렉션 수업에서 java.util. List에 의해 구현되었습니다 ArrayList.

주요 사항 :

  1. 어댑터 는 주제와 다른 인터페이스를 제공합니다. 프록시 는 동일한 인터페이스를 제공합니다. Decorator 는 향상된 인터페이스를 제공합니다.
  2. 어댑터 는 객체의 인터페이스를 변경하고 Decorator 는 객체의 책임을 향상시킵니다.
  3. 데코레이터 프록시 는 목적은 다르지만 구조는 비슷합니다
  4. 어댑터 는 디자인 된 후에 작동합니다. Bridge 는 이전에 작동하도록합니다.
  5. Bridge 는 추상화와 구현이 독립적으로 변할 수 있도록 사전에 설계되었습니다. 관련없는 클래스가 함께 작동하도록 어댑터 가 개조되었습니다.
  6. Decorator 는 서브 클래 싱없이 객체에 책임을 추가 할 수 있도록 설계되었습니다.

다양한 디자인 패턴의 예에 관한 훌륭한 SE 질문 / 기사를 살펴보십시오.

데코레이터 패턴을 사용하는시기

브리지 패턴은 언제 사용합니까? 어댑터 패턴과 어떻게 다릅니 까?

프록시와 데코레이터 패턴의 차이점


답변

그것들은 매우 비슷하며, 그들 사이의 선은 매우 회색입니다. c2 위키에서 프록시 패턴데코레이터 패턴 항목 을 읽는 것이 좋습니다 .

이 글의 내용과 토론은 매우 광범위하며 다른 관련 기사로 연결됩니다. 그건 그렇고, c2 위키는 다른 패턴 사이의 뉘앙스에 대해 궁금 할 때 탁월합니다.

c2 항목을 요약하면 데코레이터가 동작을 추가 / 변경하지만 프록시는 액세스 제어 (게으른 인스턴스화, 원격 액세스, 보안 등)와 더 관련이 있습니다. 그러나 내가 말했듯이, 그들 사이의 선은 회색이며, 데코레이터로 쉽게 볼 수 있고 그 반대로도 볼 수있는 프록시에 대한 언급이 있습니다.


답변

네 가지 패턴은 모두 내부 객체 / 클래스를 외부 패턴으로 감싸는 것을 포함하므로 구조적으로 매우 유사합니다. 목적에 따라 차이점을 설명하겠습니다.

  • 대리 는 외부에서 내부로의 액세스를 캡슐화합니다.
  • 데코레이터 는 외부의 내부 동작을 수정하거나 확장합니다.
  • 어댑터 는 인터페이스를 내부에서 외부로 변환합니다.
  • 브리지 는 가변 동작 부분 (외부)과 가변 또는 플랫폼 종속 부분 (내부)을 분리합니다.

내부 객체와 외부 객체 간의 인터페이스 변형에 따라

  • 에서 프록시 인터페이스는 동일하다.
  • 에서 실내 장식 인터페이스와 동일하다.
  • 어댑터 인터페이스 에서 형식은 다르지만 동일한 목적을 달성하십시오.
  • 에서 브릿지 인터페이스는 다른 개념이다.