1

我花了最后一天试图找出最适合我的特定场景的模式,我一直在状态模式和策略模式之间折腾。当我在 Internet 上阅读示例时,它非常有意义……但尝试将其实际应用于您自己的问题是另一种技能。我将描述我的场景和我面临的问题,希望有人能指出我正确的方向。

问题:我有一个具有不同同步状态的基础对象:即最新、旧、从未发布、未发布等。现在,根据对象所处的状态,行为会有所不同,例如,您无法获取基础对象的最新版本从未发表过。在这一点上,状态设计模式似乎最适合......所以我已经实现了它,现在每个状态都有 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 个子对象 x 5 个不同的状态),这看起来绝对是疯狂的......因此我在这里!

任何帮助将不胜感激。如果令人困惑,请告诉我,以便我澄清!

干杯

4

2 回答 2

0

让我们重新考虑一下,完全。

1)你有一个本地的“句柄”,用于一些你并不真正拥有的数据。(其中一些被存储或发布在别处)。

2)也许Handle,就是我们之前所说的“状态”——一个简单的通用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/文档可以针对不同类型的内容进行子类型化。

我敢肯定,这是更正确的解决方案。


[以前] 将 'State' 与您的 'Document' 对象保持一定程度的分离(我们称它为 Document,因为我们需要给它命名——而您没有指定。)

从 BaseDocument 开始构建您的层次结构,拥有一个 BaseDocument.State 成员,并使用对其 Document 实例的引用创建 State 对象——因此他们可以访问并处理详细信息。

本质上:

  • BaseDocument <--friend--> 状态
  • 文档子类型继承自 BaseDocument。
  • 文档层次结构中受保护的方法和成员,使状态能够做任何它需要做的事情。

希望这可以帮助。

于 2013-05-04T05:30:44.120 回答
0

许多设计模式可用于此类架构问题。不幸的是,您没有给出如何发布的示例。但是,我将陈述一些好的设计:

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

  2. 不要将 Publish 方法DocumentState放在 中, BaseDocument而是放在 中。从逻辑上讲,Publish 方法必须是 ofBaseDocument而不是 DocumentState 的一部分。

  3. 让其他服务类来处理Publishing(发布服务)。您可以通过使用抽象工厂模式来实现它。这样,您需要创建 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. 使用组合而不是继承。您为每个状态设计每个界面,然后将其组合到文档中。综上所述,你可以拥有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
        }
    }
    

可能还有其他可用的设计,但这取决于您访问存储库的方式。

于 2013-05-06T02:01:07.100 回答