在Chain of Responsibility模式中使用共享组件的最佳方式

时间:2015-11-26 08:45:22

标签: c# oop design-patterns chain-of-responsibility

我的责任链模式存在问题。 所有处理程序都实现了这个类:

5.6.16-log

然后我实施/// <summary> /// Chain of Responsibility pattern /// </summary> abstract public class ChainHandler { protected LogWrapper Log; protected ChainHandler successor; /// <summary> /// SetSuccessor /// </summary> private void SetSuccessor(ChainHandler successor) { this.successor = successor; } protected oAPI NotImplemented { get { return new oAPI(HTTPCodes.NotImplemented); } } /// <summary> /// Set Successor to the end of chain /// </summary> /// <param name="successor">Handler</param> public void Add(ChainHandler successor) { if (this.successor == null) SetSuccessor(successor); else { this.successor.Add(successor); } } protected oAPI ReferToSuccessor (iAPI request) { if (successor != null) return successor.HandleRequest(request); return NotImplemented; } /// <summary> /// output API builder /// </summary> /// <param name="code">HTTP code</param> /// <returns></returns> protected oAPI RB(HTTPCodes code, string messsage = null, string data = null, bool hasError = false) { return new oAPI(Shared.User, code, message) { Data = data, HasError = hasError }; } /// <summary> /// Serializer (JSON) /// </summary> public Func<object, string> Serializer { get; set; } /// <summary> /// Handle request /// </summary> /// <param name="request">request</param> /// <returns>result</returns> public abstract oAPI HandleRequest(iAPI request); }

DocHandler

public class DocHandler:ChainHandler { public DocChain() { Log = new LogWrapper(this); } public override oAPI HandleRequest(iAPI request) { switch (request.Comand) { case iAPI.Target.GetModel: return GetModel(request.DocID); } return ReferToSuccessor(request); } private Doc GetDoc(int id) { Log.Debug("get document by id: " + id); using (var unit = UnitOfWork.Create()) { var repository = unit.GetRepository<Doc>(); Doc doc = repository.Get(id); if (doc == null) { Log.Error("Document not found"); throw new DocumentNotFoundException(); } return doc; } } public oAPI GetModel(int DocId) { var Model = GetDoc(); return RB(HTTPCodes.OK, data: Serializer( Model)); } }

CloudHandler

我的问题是找到在处理程序之间共享方法和属性的最佳方法。 现在我使用静态类SharedComponents,其中每个处理程序委托自己的方法。

 public class CloudHandler:ChainHandler
    {
        private IDAVService _service;
        private string RemoteRepository;
        public CloudChain(IDAVService service)
        {
            Log=new LogWrapper(this);
            _service=service;
        }

        public override oAPI HandleRequest(iAPI request)
        {
            switch (request.Comand)
                    {
                    case iAPI.Target.UploadModel:
                    return Upload(request.DocID,request.VersionID);
                    case iAPI.Target.DownloadModel:
                    return Download(request.VersionID, request.DocID);
                    }
            return ReferToSuccessor(request);
        }
        public oAPI Upload(int DocID,int VersionID)
        {
            // Need to get model from DocHandler
            var model = ???
            service.Upload(model);
            return RB(HTTPCodes.OK);
        }
        public oAPI Download(int DocID,int VersionID)
        {
            // Need to get model from DocHandler
            var model = ???
            service.Download(model);
            return RB(HTTPCodes.OK);
        }
    }

在DocHandler中,我委托方法public static class SharedComponents { public static Func<int, Doc> GetDoc; } ,然后在CloudHandler SharedComponents.GetDoc = this.GetDoc;中使用它。这是将代表写入数百个共享方法的spagetti。

但我是如何测试的呢?我必须初始化所有处理程序(因为var Model = SharedComponents.GetDoc(docid)使用A方法而B可能会使用B等方法)来测试方法。恐怖!

我尝试将共享方法设置为静态使用,如C。但这种解决方案打破了依赖倒置原则。如果某些共享方法使用上下文(如var Model = DocHandler .GetDoc(docid)中的session),我需要在测试中再次初始化所有处理程序!

1 个答案:

答案 0 :(得分:2)

应用责任链模式的主要目的之一是使一些步骤彼此独立。目标是能够更改步骤的顺序或添加新步骤,而无需更改现有步骤。

在您的方法中,即使您在共享类上使用委托,也会引入从CloudHandlerDocHandler的强依赖关系,因为只有在设置了委托时它才能运行。

为了解决这个问题,我建议从处理程序中提取共享方法,并使用虚方法或接口将它们移动到一个或多个辅助类。您可以在构造期间将所需的实例注入到处理程序中,而不是在处理程序中创建类的实例。你提到了数百种共享方法。以一种好的方式对方法进行分组非常重要,这样您就不会有太多的辅助类/接口,并且您不必在特定的Handler类中注入太多。

在您的示例中,您将为Docs创建以下帮助程序类:

internal class DocHelper
{
    internal virtual Doc GetDoc(int docId) 
    { 
        // ...
    }

    // Other methods as required
}

DocHandler和CloudHandler在其构造函数中获取一个实例并使用此实例来获取文档,例如:

public class DocHandler : ChainHandler
{
    private readonly DocHelper docHelper; 

    public DocHandler(DocHelper docHelper)
    {
        Log = new LogWrapper(this); 
        this.docHelper = docHelper;
    }
    // ...
    public oAPI GetModel(int DocId)
    {
        var Model = docHelper.GetDoc();
        return RB(HTTPCodes.OK, data: Serializer(
        Model));
    }
    // ...
}

这种方法使您可以在测试处理程序时提供模拟助手类。