1

전략 패턴을 통해 읽었으며이를 구현하려고했지만 개방형 원칙을 위반한다고 생각하는 전략 구현을 결정하는 데 주저했습니다.전략 패턴 및 개방형 원칙 충돌

전략 패턴에서 우리는 인터페이스를 코딩하고 클라이언트 상호 작용을 기반으로 전략 구현을 전달합니다. 우리는 클라이언트가 위의 오픈 폐쇄 원칙에 따라 이제

IStrategy str; 
    if(stragety1) { 
    str = new Strategy1() 
    } else if (stragety2) { 
    str = new Strategy2() 
    } and so on.. 
str.run() 

같은 것을 선택 전략 조건을 사용하여 결정해야합니다, 그래서 우리가 전략의 무리가 있다면 지금

는 확장 에게 열려 있지만, 그렇지 않습니다 수정 종료

향후 다른 전략 (확장)을 추가해야하는 경우이 코드를 변경해야합니다.

이 방법을 피할 수 있습니까? 아니면 전략 패턴을 구현해야합니까?

+0

내 경험상 공개/폐쇄 원칙은 실제로 거의 가치가 없습니다. 기본 구현에는 새로운 코드를 추가하지 않고 나중에 사용자 정의 할 수있는 아키텍처 후크가 있습니다 (새로운 사용자 정의 부분에 새로운 코드 만 있음). 이것이 실전에서 실패하는 주된 이유는 코드가 야생에서 벗어나고 아무도 계획하지 않은 확장 성의 문제에 부딪 힐 때까지 아키텍처 훅에서 고려해야 할 가변성의 차원이 무엇인지 모를 수 있다는 것입니다. – ely

+0

당신이 그들을 너무 많이 계획하려고한다면, 높은 수준의 추상화가 가능한 건축용 수프로 끝나지 만, 그것이 옳은 추상인지 아닌지는 알지 못합니다. (또한 유용성과 유지 보수성을 심하게 손상시킬 수도 있습니다). 결국 가변성의 차원이 될 가능성이 매우 높은 몇 가지 항목에 대해 사용자 지정 가능성을 구축하려고 시도 할 수 있으며 나머지 부분에서는 해결하기 위해 소스 코드를 수정해야하는 것이 일반적으로 가장 좋은 방법입니다 그것. – ely

+1

코드가 내게 공장 패턴처럼 보입니다. – bpjoshi

답변

2

실제로 수정되지 않았지만 초기화하는 방법 때문입니다. 값 (enum?)을 사용하여 어떤 전략 하위 클래스를 사용해야하는지 결정합니다. @bpjoshi는 comment을 지적 했으므로 이는 Factory 패턴과 같습니다.

위키 피 디아는 전략 패턴이 어쩌면 방해가 될지 모른다면 support the Open/Closed Principle 일 수 있음을 설명합니다.
이 예에서는 Brake 전략이있는 Car 클래스를 사용합니다. ABS가있는 일부 자동차는 브레이크를 밟지 만 그렇지 않은 자동차도 있습니다. 다른 Car 하위 클래스와 인스턴스에는 제동을위한 다양한 전략이 주어질 수 있습니다.

수정을 위해 코드를 닫으려면 전략을 다르게 선택해야합니다. 새로운 행동이나 하위 클래스가 정의 된 장소에서 전략을 선택하려고합니다. 특정 전략 하위 클래스가 코드가 확장되는 지점에 적용되도록 코드를 리팩토링해야합니다.

+1

위키 문서는 내가 찾고있는 대답을 설명합니다. –

0

수정을 위해 Closed에 대한 오해가 있다고 생각합니다. 1988 년

, 메이어는 말했다 : 작동
소프트웨어가해야 할 때 응용 프로그램이 새로운 기능으로 확장 할 때 변경할 수 없습니다.

및 Rober C. Matrin이 말했다 :

이 정의는 분명히 기한이되어있다. 그것에 대해 매우 신중하게 생각하십시오. 시스템에있는 모든 모듈의 동작을 수정하지 않고 확장 할 수 있다면 이전 코드을 수정하지 않고 의 새로운 기능을 추가 할 수 있습니다. 기능은 새로운 코드을 작성하여 추가 한 입니다. https://8thlight.com/blog/uncle-bob/2014/05/12/TheOpenClosedPrinciple.html

이전 코드를 수정하지 않고 일부 새 코드를 추가해도 개방형 기본 원칙과 충돌하지 않습니다.

-1

당신이 말하는 결정은 공장 수업의 책임이어야한다고 생각합니다.다음은 몇 가지 예제 코드입니다 :

public interface ISalary 
{ 
    decimal Calculate(); 
} 

public class ManagerSalary : ISalary 
{ 
    public decimal Calculate() 
    { 
     return 0; 
    } 
} 

public class AdminSalary : ISalary 
{ 
    public decimal Calculate() 
    { 
     return 0; 
    } 
} 

public class Employee 
{ 
    private ISalary salary; 

    public Employee(ISalary salary) 
    { 
     this.salary = salary; 
    } 

    public string Name { get; set; } 

    public decimal CalculateSalary() 
    { 
     return this.salary.Calculate(); 
    } 
} 

Employee 클래스는 전략 패턴을 사용하고 생성자를 통해 주입을 통해 새로운 전략 유형 (ISalary 구현)에 열려 즉, 오픈/청산 원칙을 따르지만 폐쇄 가감. 이것은 매우 간단한 공장 패턴입니다

public enum EmployeeType 
{ 
    Manager, 
    Admin 
} 

public class EmployeeFactory 
{ 
    public Employee CreateEmployee(EmployeeType type) 
    { 
     if (type == EmployeeType.Manager) 
      return new Employee(new ManagerSalary()); 

     else if (type == EmployeeType.Admin) 
      return new Employee(new AdminSalary()); 

     etc 

    } 
} 

: 누락 된

이 작품은, 같은 것을 직원 객체를 생성하는 코드입니다. 이를 수행하는 더 좋은 방법이 있지만 개념을 설명하는 가장 간단한 방법입니다.

+0

전략을 선택하기 위해'if-else'를 사용하는 것은 코드가 OCP를 깨뜨리지 못하게하는 아주 나쁜 생각입니다. –

+0

@Igor Soloydenko - 네, 저는 이것을 수행하는 더 좋은 방법이 있음을 언급했습니다. 전략 픽킹 로직이 실제 전략 패턴의 일부가 아닌 이유를 설명하려고했습니다. –

2

1) 콘크리트을 선택/생성하여 사용에서 분리해야합니다. I. e. selectStrategy을 사용하여 (생성자) 매개 변수 등으로 전달하십시오.

2) 조건부 생성을 완전히 피할 방법이 없지만 숨길 수 있습니다 (예 : 상태 => 전략 매핑에 사전 사용). 응용 프로그램의 다른 레벨로 변경하십시오. 마지막 접근 방식은 매우 강력하고 유연하지만 작업에 따라 다릅니다. 어떤 경우에는 그것을 사용하는 동일한 레벨에서 선택/생성을 할 수 있습니다. 다른 경우에는 최상위/최하위 수준으로 위임을 선택/생성하는 결과를 초래할 수도 있습니다.

2.1) Registry 패턴을 사용할 수 있으며 새로운 전략을 추가 할 때 '핵심'개체의 수정을 피할 수 있습니다.