[design-patterns] 브리지 패턴과 전략 패턴의 차이점은 무엇입니까?

나는 dofactory , wikipedia 및 많은 사이트 에서 많은 기사를 읽으려고 노력했습니다 . 브리지 패턴과 전략 패턴의 차이점에 대해 전혀 모릅니다.

둘 다 구현에서 추상화를 분리하고 런타임에 구현을 변경할 수 있음을 알고 있습니다.

하지만 어떤 상황에서 전략을 사용해야하는지, 어떤 상황에서 브리지를 사용해야하는지 여전히 잘 모르겠습니다.



답변

의미론. 에서 위키 피 디아 :

전략 패턴의 UML 클래스 다이어그램은 Bridge 패턴의 다이어그램과 동일합니다. 그러나이 두 가지 디자인 패턴은 의도가 동일하지 않습니다. 전략 패턴은 행동을위한 것이지만 브리지 패턴은 구조를위한 것입니다.

컨텍스트와 전략 간의 결합은 추상화와 Bridge 패턴의 구현 간의 결합보다 더 엄격합니다.

내가 이해했듯이 외부 소스에서 제공 할 수있는 동작을 추상화 할 때 전략 패턴을 사용하고 (예 : config는 일부 플러그인 어셈블리를로드하도록 지정할 수 있음), 사용할 때 브리지 패턴을 사용하고 있습니다. 코드를 좀 더 깔끔하게 만들기 위해 동일한 구조를 사용합니다. 실제 코드는 매우 유사하게 보일 것입니다. 단지 약간 다른 이유로 패턴을 적용하는 것 입니다.


답변

브리지 패턴은 구조적 패턴입니다 (소프트웨어 구성 요소를 어떻게 구축합니까?). 전략 패턴은 동적 패턴입니다 (소프트웨어에서 동작을 어떻게 실행 하시겠습니까?).

구문은 비슷하지만 목표는 다릅니다.

  • 전략 : 작업을 수행하는 더 많은 방법이 있습니다. 전략을 사용하면 런타임에 알고리즘을 선택할 수 있으며 컴파일 타임에 많은 부작용없이 단일 전략을 수정할 수 있습니다.
  • Bridge : 인터페이스와 클래스의 계층을 분할하고 추상 참조와 결합 할 수 있습니다 ( 설명 참조 ).

답변

전략:

  • 전략에 연결된 컨텍스트 : 컨텍스트 클래스 (추상적이지만 실제로는 인터페이스가 아닙니다! 전체 구현이 아닌 특정 동작을 캡슐화하려는 경우)는 전략 인터페이스 참조 및 전략 동작을 호출하는 구현 을 알고 / 포함합니다 . 그것.
  • 의도는 런타임에 동작을 바꾸는 기능입니다.

    class Context {
    
         IStrategy strategyReference;
    
         void strategicBehaviour() {
    
            strategyReference.behave();
         }
    
    }
    

다리

  • 구현에 연결되지 않은 추상화 : 추상화 인터페이스 (또는 대부분의 동작 추상이있는 추상 클래스)는 구현 인터페이스 참조를 알거나 포함하지 않습니다.
  • 의도는 구현에서 추상화를 완전히 분리하는 것입니다.

    interface IAbstraction {
    
        void behaviour1();
    
        .....
    
    }
    
    interface IImplementation {
    
         void behave1();
    
         void behave2();
    
         .....
    
    }
    
    class ConcreteAbstraction1 implements IAbstraction {
    
          IImplementation implmentReference;
    
          ConcreteAbstraction1() {
    
               implmentReference = new ImplementationA() // Some implementation
    
          }
    
          void behaviour1() {
    
                implmentReference.behave1();
    
          }
    
          .............
    
    }
    
    class ConcreteAbstraction2 implements IAbstraction {
    
          IImplementation implmentReference;
    
          ConcreteAbstraction1() {
    
               implmentReference = new ImplementationB() // Some Other implementation
    
          }
    
          void behaviour1() {
    
                implmentReference.behave2();
    
          }
    
          .............
    
    }
    

답변

저도 같은 생각을하고 있었지만 최근에는 브리지를 사용해야했고 브리지가 전략을 사용하고 컨텍스트에 추상화를 추가하여 나중에 클라이언트를 변경하지 않고도 더 많은 변경을 수행 할 수 있다는 것을 깨달았습니다. 추상화없이 Strategy를 사용하면 디자인이 유연하지 않아 나중에 클라이언트를 변경해야 할 수 있습니다. 그러나 전체 교량을 사용하면 디자인이 훨씬 더 유연 해집니다. 여기에서 Strategy에서 Bridge 로의 전환이 어떻게 더 많은 유연성을 제공하는지 확인할 수 있습니다. 또한 이제 “비자”와 “마스터”는 카드뿐만 아니라 휴대폰과 칩에서도 사용할 수 있다고 가정합니다. 브리지를 사용하면 해당 지원을 추가하는 것이 훨씬 쉽습니다.

전략 VS Bridge


답변

교량 : (구조적 패턴)

브리지 패턴은 추상화와 구현을 분리하고 둘 다 독립적으로 변할 수 있습니다.

다음과 같은 경우이 패턴을 사용합니다.

  1. 추상화와 구현은 컴파일 타임에 결정되지 않았습니다.
  2. 추상화 및 구현은 독립적으로 변경되어야합니다.
  3. 추상화 구현의 변경 사항은 호출자 응용 프로그램에 영향을주지 않아야합니다.
  4. 고객은 구현 세부 사항으로부터 격리되어야합니다.

전략 : (행동 패턴)

전략 패턴을 사용하면 런타임에 알고리즘 제품군의 여러 알고리즘간에 전환 할 수 있습니다.

다음과 같은 경우 전략 패턴을 사용합니다.

  1. 여러 버전의 알고리즘이 필요합니다.
  2. 클래스의 동작은 런타임에 동적으로 변경되어야합니다.
  3. 조건문 피하기

관련 게시물:

Bridge Pattern은 언제 사용합니까? 어댑터 패턴과 어떻게 다릅니 까?

전략 패턴의 실제 사례


답변

디자인 패턴 유형

  • 행동 : 패턴은 클래스 또는 객체가 상호 작용하고 책임을 분배하는 방식을 특성화합니다.
  • 구조적 : 패턴은 클래스 또는 객체의 구성을 처리합니다.
  • Creational : 패턴은 객체 생성 과정에 관심이 있습니다.

교량 (구조)

추상화를 구현에서 분리하여 각각 다를 수 있습니다. 독립적으로.
여기에 이미지 설명 입력

리모컨을 가져 가세요. 리모컨에는 1-6 버튼이 있습니다. 이것은 위 다이어그램의 구체적인 클래스입니다. 리모컨이 TV 또는 DVD에 사용되는지 여부에 따라 각 버튼이 다르게 작동합니다. 각 버튼의 기능은 구현 자 인터페이스의 구현에서 추상화됩니다.

이를 통해 각 장치에서 리모컨이 작동하는 방식을 변경할 수 있습니다.

전략 (행동)

알고리즘 패밀리를 정의하고 각 알고리즘을 캡슐화하여 상호 교환 가능하게 만드십시오.
여기에 이미지 설명 입력

전략에서 우리가 원격 시나리오를보고 있다면. “상태”는 컨텍스트의 상태 참조를 변경하여 교체하는 전체 원격입니다. “concreteStateA”(TV 원격) “concreteStateB”(DVD 원격)입니다.

추가 자료 :


답변

  1. Strategy Pattern은 행동 결정에 사용되며 Bridge Pattern은 구조 결정에 사용됩니다.

  2. Brigde Pattern은 구현 세부 사항에서 추상 요소를 분리하는 반면, 전략 패턴은 알고리즘을보다 상호 교환 가능하게 만드는 데 관심이 있습니다.

UML의 전략 패턴

UML의 Brigde 패턴

Swift의 전략 패턴 :

protocol PrintStrategy {
   func print(_ string: String) -> String
}

class Printer {
   let strategy: PrintStrategy

   init(strategy: PrintStrategy) {
      self.strategy = strategy
    }

  func print(_ string: String) -> String {
     return self.strategy.print(string)
  }
}

class UpperCaseStrategy: PrintStrategy {
    internal func print(_ string: String) -> String {
        return string.uppercased()
    }
}

class LowerCaseStrategy: PrintStrategy {
    internal func print(_ string: String) -> String {
        return string.lowercased()
    }
}

var lower = Printer(strategy: LowerCaseStrategy())
lower.print("I love Software Patterns")

var upper = Printer(strategy: UpperCaseStrategy())
upper.print("I love Software Patterns")

Swift의 Brigde 패턴 :

protocol Appliance {
   func run()
}

protocol Switch {
   let appliance: Appliance {get set}
   func turnOn()
}

class RemoteControl: Switch {
   var appliance: Appliance

   init(appliance: Appliance) {
       self.appliance = appliance
   }

   internal func turnOn() {
      appliance.run()
   }
}

class TV: Appliance {
   internal func run() {
      print("TV is ON")
   }
}

class Stereo: Appliance {
   internal func run() {
      print("Stereo is ON")
   }
}

var tvRemote = RemoteControl.init(appliance: TV())
tvRemote.turnOn()

var stereoRemote = RemoteControl.init(appliance: Stereo())
stereoRemote.turnOn()