상태 패턴을 사용하는 객체를 다음 상태로 어떻게 전환해야합니까?

StackOverflow https://stackoverflow.com/questions/747961

  •  09-09-2019
  •  | 
  •  

문제

일련의 정의 된 상태를 통과하는 주문 클래스가 있습니다. 이를 돕기 위해 주문 개체에 iorderstate 인터페이스를 구현하는 현재 상태 멤버가 있도록 상태 패턴을 구현했습니다. 그런 다음 Orderstatenew, OrderstatedLivered 등과 같은이 인터페이스의 구체적인 구현이 있습니다.

내 질문은 상태 간 순서 대상을 전환하는 올바른 방법은 무엇입니까? 외부 서비스가 상태를 설정할 수있는 Order.setState () 메소드를 갖는 것이 허용됩니까? 상태 변경을 결정하는 기준은 주문 객체의 외부에서 저장되므로 이것은 명백한 대답 인 것처럼 보이지만 이와 같이 근본적인 것을 변경하기 위해 내 객체에 공개 메소드를 갖는 것에 대해 약간 불안합니다.

추가 설명처음에 패턴을 올바르게 사용하는지 궁금하기 때문에 구현에 대한 자세한 내용을 추가하는 것이 유용 할 것이라고 생각했습니다. 주문을 작성하고 승인하기위한 Pulbic API는 다음과 같습니다.

Dim orderFacade As New OrderFacade
Dim order = orderFacade.createFrom(customer)

' Add lines etc

' This will validate the order and transition it to status 'Authorised'
Dim valid = orderFacade.Authorise(order)

' This will commit the order, but only if it is at status 'Authorised'
Dim result = orderFacade.Commit()

OrderFacade.authorise () 함수는 다음과 같습니다

Public Function Authorise(ByRef originalOrder As Order) As ValidationSummary

    If originalOrder.CurrentState.CanAuthorise() Then

       Dim validator = OrderValidatorFactory.createFrom(originalOrder)
       Dim valid = validator.ValidateOrder(originalOrder)

      If valid.IsValid Then
          originalOrder.SetOrderStatus(OrderStatus.Authorised)
      End If

     Return valid

    End If

 End Function

보시다시피, 현재 상태 멤버는 객체에 유효한 활동을 결정하는 현재 iorderstate 구현입니다. 이것이 주문 경관보다는 전환을 결정하는 데 책임이 있는지 궁금합니다.

도움이 되었습니까?

해결책

과제보다는 암시 적으로 상태를 변경하는 것을 고려하십시오.

내가 본 것 중 거의 모든 경우에, 국가는 다른 속성에서 유추 될 수 있습니다 (희망적으로 클래스 내에서). 그렇다면 상태를 지속하지 말고 필요할 때 파생하십시오. 그렇지 않으면 추론 된 값과 할당 된 값 사이의 문제 불일치로 종종 끝날 것입니다. (그리고 내 경험상 "파생 된"은 항상 옳습니다.)

(복잡성은 종종 클래스의 트랜잭션 로그를 검토하고 가장 최근의 이벤트를 고려하는 것입니다. 그러나 어쨌든 그만한 가치가 있습니다.)

다른 팁

setState () 메소드는 추가 상태로 주문을 확장하고 계측 변경 사항을 확장 할 때 장점이 있지만 권장하지는 않습니다. 그만큼 상태 패턴 다른 클래스에 상태의 인터페이스를 제시하는 방법이 아니라 별도의 클래스에서 별개의 상태에 특정한 행동을 수집하는 것입니다.

주문의 경우 자연스럽게 나오는 비즈니스 이벤트 (예 : 확인, 승인, 배송 통지, 배송, 인보이스 & C)에 대해 생각하고 주변의 명시 적 인터페이스를 설계하십시오. 정확히 인터페이스를 설계하는 방법은 응용 프로그램 로직 구조의 구조 및 다른 레이어에서 사용되는 방법에 따라 다릅니다. 전형적인 답변은 각 비즈니스 이벤트 (예 : 확인 (), alfactewedge (), shipDatechanged ())에 대한 추상 방법을 정의하는 것입니다. 예를 들어 C#을 사용하는 경우 주문 개체에서 들어오는 이벤트와 나가는 이벤트를 사용하기로 결정할 수 있습니다. 또는 혼합물이나 조합을 시도해 볼 수 있습니다. 요점은 setorderstate () 인터페이스가 매우 설명 적이 지 않으며 서투른 구현으로 이어질 가능성이 높다는 것입니다 (각 오더 스테이트 클래스에서 큰 방법).

다시 한 번, 다른 상태 변경 사항에 대한 코드가 많지 않으면 클래스 내부의 SetState () 메소드 (각 특정 방법 또는 이벤트에서 호출)는 괜찮을 수 있습니다. 외부 인터페이스. 단점은 내부 iorderstate 인터페이스의 메소드와 외부에서 노출 된 순서 인터페이스 사이에 약간의 겹침을 얻을 수 있다는 것입니다.

이것은 판단 전화이지만, 내가 당신이라면, 나는 당신의 본능과 함께 당신의 주 구현의 세부 사항을 고객에게 노출시키지 않기 위해 갈 것입니다. 주문 클래스를 사용하는 코드는 읽을 수 있고 이해할 수 있어야합니다.

예를 들어 비공개 패키지를위한 방법의 가시성을 줄일 수 있습니다. 그러나 귀하의 경우 나는 이것이 유일한 방법이라고 생각합니다. 다른 방법은 상태 기계를 구현하고 차세대 (InputParameter) 메소드 그룹이 해당 상태로 전환되는 부모 추상 클래스를 갖는 또 다른 방법이라고 생각합니다.

나는 이것에 대한 "올바른"대답이 있다고 생각하지 않습니다. 그것은 주 머신에 선택한 아키텍처에 실제로 달려 있습니다. 상태 변경 상태에 대한 모든 논리가 주문 클래스 내에서 캡슐화되면 SetState 방법을 노출시키는 것은 실용이 좋지 않을 것이라고 말합니다. 그러나 이미 주문 클래스 외부에 국가 결정 논리를 이미 배치 했으므로 공개 세트 스테이트 방법을 노출시키는 것이 적절한 것 같습니다.

물론, 당신의 다른 선택은 국가 결정 논리를 주문 클래스로 옮기는 것입니다. 그러나 당신이 게시 한 내용에 따라 그것은 매우 복잡한 클래스를 만드는 것처럼 보입니다.

어쨌든 간단히 말해서, 패턴은 실제로 코드를 건축하고 단단하고 빠른 규칙을 설정하지 않도록 도와줍니다. 패턴에 대한 아키텍트가 아니라 가장 잘 작동하는 방식으로 아키텍처에 패턴을 적용해야합니다.

국가 간의 전환은 수업에 있어야한다고 생각합니다.

예를 들어, 순서대로 어떤 종류의 조치를 수행 할 때, 주문은 다른 상태로 이동하는 방법을 알고 있습니다. 예를 들어:

 public void setPaid(int amount)
 {
    //Code to pay.
    this.State = new PaidState();   //State implements the IState Interface
 }

다른 대안은 이와 같은 방법을 구현하는 변압기와 같은 새로운 클래스를 만드는 것입니다.

 public class Transformer
 {
    public static void setState(Order o, IState s)
    {
         //Change the State.
    }
 }

또는 Yoy는 열거를 사용하여 상태를 설정할 수 있습니다.

 public class Transformer
 {
    public static void setState(Order o, StatesEnum s)
    {
         //Change the State.
    }
 }

그러나 나는 자신의 상태를 조작하기 위해 수업을 추천합니다. 그러나 반면에 당신이 가질 수있는 복잡성을 기억하십시오.

친애하는!

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top