2013-05-04 2 views
1

나는 특정 패턴에 가장 적합한 패턴을 찾기 위해 마지막 날을 보냈으며 상태 패턴 & 전략 패턴 사이에 던져 넣었습니다. 인터넷에서 예제를 읽을 때 그것은 완벽하게 이해됩니다 ...하지만 실제로 다른 문제를 자신의 문제에 적용하려고합니다. 내 시나리오와 내가 직면 한 문제를 설명하고 누군가가 올바른 방향으로 나를 가리킬 수 있기를 바랍니다.OO 프로그래밍 문제 - 상태 디자인 패턴

문제 : 다른 동기화 상태 (예 : 최신, 이전, 게시되지 않음, 게시되지 않음 등)가있는 기본 개체가 있습니다. 개체가 동작의 상태에 따라 달라집니다. 예를 들어 최신 버전을 가져올 수 없습니다. 게시 된 적이없는 기본 객체의 경우 이 시점에서 상태 디자인 패턴이 가장 적합하다고 생각합니다 ... 그래서 구현했고 각 상태는 CanGetLatestVersion, GetLatestVersion, CanPublish, Publish 등과 같은 메소드를가집니다.

이 시점에서 모두 좋은 것처럼 보입니다. 하지만 기본 클래스에서 파생 된 10 가지 자식 개체가 있다고 가정 해 봅시다. "publish"메서드가 각 상태에 대해 실행될 때 자식 개체의 속성이 실제로 작업을 수행하지만 각 상태를 필요로하므로 내 솔루션이 손상됩니다 기본 객체에 대한 참조 만 있습니다. 방금 C#에서 내 문제를 보여주는 샘플 프로젝트를 만드는 데 시간을 들였습니다.

public class BaseDocument 
{ 
    private IDocumentState _documentState; 

    public BaseDocument(IDocumentState documentState) 
    { 
     _documentState = documentState; 
    } 

    public bool CanGetLatestVersion() 
    { 
     return _documentState.CanGetLatestVersion(this); 
    } 

    public void GetLatestVersion() 
    { 
     if(CanGetLatestVersion()) 
      _documentState.CanGetLatestVersion(this); 
    } 

    public bool CanPublish() 
    { 
     return _documentState.CanPublish(this); 
    } 

    public void Publish() 
    { 
     if (CanPublish()) 
      _documentState.Publish(this); 
    } 

    internal void Change(IDocumentState documentState) 
    { 
     _documentState = documentState; 
    } 
} 

public class DocumentSubtype1 : BaseDocument 
{ 
    public string NeedThisData { get; set; } 
} 

public class DocumentSubtype2 : BaseDocument 
{ 
    public string NeedThisData1 { get; set; } 
    public string NeedThisData2 { get; set; } 
} 

public interface IDocumentState 
{ 
    bool CanGetLatestVersion(BaseDocument baseDocument); 
    void GetLatestVersion(BaseDocument baseDocument); 
    bool CanPublish(BaseDocument baseDocument); 
    bool Publish(BaseDocument baseDocument); 
    SynchronizationStatus Status { get; set; }  
} 

public class LatestState : IDocumentState 
{ 
    public bool CanGetLatestVersion(BaseDocument baseDocument) 
    { 
     return false; 
    } 

    public void GetLatestVersion(BaseDocument baseDocument) 
    { 
     throw new Exception(); 
    } 

    public bool CanPublish(BaseDocument baseDocument) 
    { 
     return true; 
    } 

    public bool Publish(BaseDocument baseDocument) 
    { 
     //ISSUE HERE... I need to access the properties in the the DocumentSubtype1 or DocumentSubType2 class. 
    } 

    public SynchronizationStatus Status 
    { 
     get 
     { 
      return SynchronizationStatus.LatestState; 
     } 
    } 
} 

public enum SynchronizationStatus 
{ 
    NeverPublishedState, 
    LatestState, 
    OldState, 
    UnpublishedChangesState, 
    NoSynchronizationState 
} 

나는 다음 일 것이다 그러나 나는 즉, 50 개 클래스 (어린이 10 × 5 가지 상태)를 만들어야하고 그냥 절대 미친 보인다 ... 각 자식 객체의 상태를 구현하는 방법에 대한 생각 ... 그래서 나는 왜 여기에있다!

도움을 주시면 감사하겠습니다. 혼란 스러울 경우 알려 주시기 바랍니다.

건배

+0

"* 기본 클래스에서 파생 된 10 개의 다른 하위 객체"*가 정확히 무엇을 의미합니까? 이 부분은 다소 혼란 스럽습니다. – acdcjunior

+0

문제를 설명하기 위해 몇 가지 샘플 코드를 추가했습니다.이 인스턴스에는 하위 개체가 두 개만 있습니다. 즉, DocumentSubtype1 & DocumentSubtype2 – Fred

답변

0

완전히 다시 생각해 봅시다.

1) 실제 소유하지 않은 일부 데이터에는 로컬 '처리'가 있습니다. (그 중 일부는 다른 곳에 저장되거나 게시됩니다.)

2) 구현 정보가없는 단순한 공통 API 인 Handle은 이전에 '상태'라고 불렀습니다.

3) 'CanPublish'가 아닌 'GetLatestVersion'이 BaseDocument에서 State로 위임 됨 - Handle이 특정 DocumentStorage 구현에 위임해야하는 것처럼 들립니다.

4) 외부 국 또는 저장 위치를 ​​나타내는 별도의 개체를 사용하는 저장 위치에 새로운/존재/삭제 & 상태 식별자를 캡슐화에 적합하다.

5) '버전'이 '게시 된 위치'의 일부인지 확실하지 않습니다. 또는 두 개의 독립적 인 저장 위치 인 경우 우리의 손잡이는 서로 독립적 인 위치에 대해 '저장 상태'표현을 필요로합니다. 예를 들어

:

Handle 
    - has 1 LocalCopy with states (LOADED, NOT_LOADED) 
    - has 1 PublicationLocation with Remote URL and states (NEW, EXIST, UPDATE, DELETE) 

Handle.getVersions() then delegates to PublicationLocation. 
Handle.getCurrent() loads a LocalCopy (cached), from PublicationLocation. 
Handle.setCurrent() sets a LocalCopy and sets Publication state to UPDATE. 
    (or executes the update immediately, whichever.) 

원격 저장 위치/수송선 상이한 액세스 방법 또는 LocalCopy/문서의 서브 타입이 될 수있는 콘텐츠의 다른 유형의 서브 타입 화 될 수있다.

이 메시지는 더 정확한 해결책임을 확신합니다.


[이전] (우리가 뭔가를 호출 할 필요가 있기 때문에, 이제 문서를 호출 할 수 있습니다. - 당신은 지정하지 않은) 당신의 '문서'개체에서 '주'다소 별도의 유지

BaseDocument에서 계층 구조를 빌드하고 BaseDocument.State 멤버가 있고 해당 Document 인스턴스에 대한 참조가있는 State 개체가 만들어집니다. 따라서 &에 액세스 할 수 있으므로 세부 정보 작업이 가능합니다. 기본적으로

:

  • BaseDocument는 < - 친구 -> 주
  • 문서의 하위 유형 BaseDocument에서 상속합니다.
  • 보호 된 방법 & 문서 계층 구조의 구성원은 필요한 모든 작업을 수행 할 수 있습니다.

희망이 도움이됩니다.

+0

응답 해 주셔서 감사합니다 ... 귀하의 뜻을 정확히 이해하고 있는지 확신 할 수 없습니다. 원래 게시물에 샘플 코드를 추가했습니다 ... 자세한 설명을 제공 할 수 있습니까? 건배 – Fred

0

이러한 유형의 아키텍처 문제에는 많은 디자인 패턴을 사용할 수 있습니다. 게시하는 방법에 대한 예제를 제공하지 않는 것은 불행한 일입니다. 그러나, 나는 좋은 디자인의 일부를 언급합니다 :

  1. 는 기본 문서에 추가 매개 변수를 넣고 그것을 null 허용합니다. 문서에서 사용되지 않으면 null입니다. 그렇지 않으면 값이 있습니다. 여기서 상속 할 필요가 없습니다.

  2. Publish 메서드를 DocumentState에 넣지 말고 BaseDocument을 대신 입력하십시오. 논리적으로 Publish 메서드는 DocumentState 대신 의 BaseDocument이어야합니다.

  3. 다른 서비스 클래스에서 게시 (게시자 서비스)를 처리하도록합니다. 추상 팩토리 패턴을 사용하여이 작업을 수행 할 수 있습니다. 이 방법, 당신은 1 : 1 문서 : 게시자 개체를 만들어야합니다. 일 수 있지만 각 문서 게시자를 자유롭게 수정할 수 있습니다.

    public interface IPublisher<T> where T : BaseDocument 
    { 
        bool Publish(T document); 
    } 
    
    public interface IPublisherFactory 
    { 
        bool Publish(BaseDocument document); 
    } 
    
    public class PublisherFactory : IPublisherFactory 
    { 
        public PublisherFactory(
         IPublisher<BaseDocument> basePublisher 
         , IPublisher<SubDocument1> sub1Publisher) 
        { 
         this.sub1Publisher = sub1Publisher; 
         this.basePublisher = basePublisher; 
        } 
        IPublisher<BaseDocument> basePublisher; 
        IPublisher<SubDocument1> sub1Publisher; 
    
        public bool Publish(BaseDocument document) 
        { 
         if(document is SubDocument1) 
         { 
          return sub1Publisher.Publish((SubDocument1)document); 
         } 
         else if (document is BaseDocument) 
         { 
          return basePublisher.Publish(document); 
         } 
         return false; 
        } 
    } 
    
    public class LatestState : IDocumentState 
    { 
        public LatestState(IPublisherFactory factory) 
        { 
         this.factory = factory; 
        } 
        IPublisherFactory factory; 
    
        public bool Publish(BaseDocument baseDocument) 
        { 
         factory.Publish(baseDocument); 
        } 
    } 
    
  4. Composition over inheritance을 사용하십시오. 각 인터페이스를 각 상태로 설계 한 다음 문서에서 구성하십시오. 요약하면 5 CanGetLatestVersion 및 기타 구성 클래스는 있지만 게시자 구성 클래스는 10 개입니다.

  5. 더 많이 사용하는 저장소를 기반으로 Visitor pattern을 사용할 수 있습니다. 이렇게하면 각 게시 방법을 자유롭게 수정할 수 있습니다. 그것은 하나의 클래스에서 선언된다는 것을 제외하고는 요점 3과 유사합니다. 예를 들어 :

    public class BaseDocument 
    { 
    
    } 
    public class SubDocument1 : BaseDocument 
    { 
    
    } 
    
    public class DocumentPublisher 
    { 
        public void Publish(BaseDocument document) 
        { 
    
        } 
        public void Publish(SubDocument1 document) 
        { 
         // do the prerequisite 
         Publish((BaseDocument)document); 
         // do the postrequisite 
        } 
    } 
    

다른 디자인을 사용할 수있을 수 있습니다하지만 당신은 저장소에 액세스하는 방법이에 따라 달라집니다.