2013-05-04 164 views
1

我花了最后一天的时间来尝试确定哪种模式最适合我的特定场景,并且我一直在折磨着状态模式&策略模式。当我在互联网上阅读示例时,它非常有意义......但它是另一种尝试将它应用于自己的问题的技巧。我会描述我的情况和我面临的问题,希望有人能指出我正确的方向。面向对象程序设计问题 - 状态设计模式

问题:我有一个具有不同同步状态的基础对象:即最新,旧,从未发布,未发布等。现在取决于对象在行为中的状态是不同的,例如,您无法获取最新版本对于从未发布的基础对象。在这一点上,国家设计模式似乎是最适合的...所以我已经实施了它,现在每个州都有CanGetLatestVersion,GetLatestVersion,CanPublish,Publish等方法。

这一切似乎都很好。但是可以说你有10个不同的子对象派生自基类......我的解决方案被破坏了,因为当为每个状态执行“发布”方法时,它需要子对象中的属性来实际执行操作,但是每个状态只有对基础对象的引用。我刚刚花了一些时间创建一个示例项目,说明我在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种不同的状态),而似乎只是绝对疯了...为什么我在这里!

任何帮助将不胜感激。如果它是混淆请让我知道,所以我可以澄清!

Cheers

+0

你究竟是什么意思?*“从基类派生的10个不同的子对象”*?这部分有点混乱。 – acdcjunior 2013-05-04 05:34:58

+0

我已经添加了一些示例代码来帮助说明问题。在这种情况下,只有两个子对象,即DocumentSubtype1&DocumentSubtype2 – Fred 2013-05-04 05:56:41

回答

0

让我们重新思考这个问题。

1)你有一个本地'句柄',对一些你并不真正拥有的数据。 (其中一些存储或发布在其他地方)。

2)也许句柄,就是我们之前称之为“状态”的 - 一个简单的通用API,没有实现细节。

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 < --friend - >国家
  • 文档亚型从BaseDocument继承。
  • 受保护的方法&文档heirarchy中的成员,使状态可以做任何需要的操作。

希望这会有所帮助。

+0

感谢您的回复......我不确定我确切地理解您的意思。我在原帖中添加了一些示例代码......你能提供进一步的解释吗?干杯 – Fred 2013-05-04 05:55:46

0

许多设计模式都可以用于这种架构问题。不幸的是,你没有举例说明你如何进行发布。不过,我会说出一些好的设计:

  1. 把附加参数基本文档,并使其 空。如果未在文档中使用,则为空。否则,它 有价值。这里你不需要继承。

  2. 请勿将发布方法置于DocumentState,而应将其放入 BaseDocument。逻辑上,发布方法必须是BaseDocument的 部分,而不是DocumentState。

  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 
        } 
    } 
    

可能有其他的设计可供选择,但你怎么访问你的仓库它是依赖于。