【问题标题】:"Handler" pattern?“处理程序”模式?
【发布时间】:2009-03-13 04:06:48
【问题描述】:

我遇到了一种被称为“处理程序模式”的设计模式,但我在任何地方都找不到对该模式的任何真正引用。它基本上只是一个单一方法接口,允许您轻松扩展后端的功能,而无需重新编译客户端。对于必须处理许多不同类型的请求的 Web 服务可能很有用。这是一个例子:

public interface IHandler
{
    IDictionary<string, string> Handle(IDictionary<string, string> args);
}

args 通常会包含一个键,例如“Action”,其值告诉实现该做什么。可以传入额外的参数来为 impl 提供更多信息。然后 impl 传回客户端“应该”理解的任意参数列表。

这是一种反模式,还是另一种伪装的模式?是否推荐这种类型的设计?

编辑: 更多信息:按照我看到的实现方式,“根”处理程序将充当其他具体处理程序的调度程序(也许?)。根处理程序有一个“HandlerResolver”,它根据消息的内容决定哪个具体的处理程序应该获取消息。也许它实际上就像一个“调度程序”模式,虽然我也不知道这是否真的是一个模式。我猜它的根也可能有一个责任链模式,它允许你将一堆具体的处理程序链接在一起,然后让他们决定哪个处理它。

【问题讨论】:

  • 处理程序模式将业务流程抽象为响应请求而执行的某些操作。当客户端不必知道处理程序的具体实现并且不能通过更显式的接口更好地表示操作时,这种抽象效果很好。 Javier 说它作为闭包的属性很有用也是正确的。它通常用于大型系统中以减少需要高扩展性的耦合。事件总线中使用的订阅者模式非常相似,但会为单个请求调用许多处理程序。

标签: c# .net design-patterns


【解决方案1】:

这是对没有闭包的语言进行闭包的 OOP 方式。它没有“模式”名称,因为在函数式语言中它是显而易见的工作方式。在 OOP 语言上,OTOH,你必须做一些工作,所以它似乎是一个可命名的成语。 “处理程序”听起来不错。

(这不是单例,顺便说一句)

【讨论】:

    【解决方案2】:

    我以“SingletonRegistry”的名义使用它

    this thread

    我已经用过几次了。特别是当要采取的行动是未知的(在设计的第一阶段)或应用程序应该支持极大的灵活性时。

    我从文件或数据库中加载字典,并创建一个类的单个实例来处理特定“键”下的请求。

    我发现这个class also 在网上搜索该名称。

    看起来不一样?

    【讨论】:

      【解决方案3】:

      因为您的帖子中有“动作”一词,我被引导相信这可能是命令模式的一部分。查看 Wiki 并搜索“处理程序”...也许这会提供更多见解。

      http://en.wikipedia.org/wiki/Command_pattern

      【讨论】:

      • 是的,命令模式是我对这是什么的第一个猜测。我认为命令排序在内部使用与“执行”方法类似的东西。
      【解决方案4】:

      我不知道它是否真的被推荐,但实际上我不得不在我编写的一些 MATLAB 应用程序中使用这种模式来模拟对象的类似引用的行为(现在对于新版本是不必要的) .

      具有讽刺意味的是,我实际上将函数称为“处理程序”。我的对象只存储了一个包含函数句柄引用 (@handler) 的字段,而方法只是调用此函数的包装器。例如,对象的重载 GET 函数只会调用:

      object.handler('get',...input argument list...)
      

      我不确定这在其他语言中是否被认为是“好的”设计选择。我出于必要选择了它,因为它是我在 MATLAB 中创建类似引用的行为的唯一方法(处理函数可以访问初始化数据的工作区,我不必传入和传出各种方法调用)。最新版本的 MATLAB 现在有一个 HANDLE 类,可以更简洁地完成这些工作。

      【讨论】:

        【解决方案5】:

        我认为 COM 可以更好地实现避免重新编译的目标 影响设计。您从中获得了哪些额外的灵活性:

        IHandler UserHandler = ...;
        
        Dictionary<string,string> result = UserHandler.Handle(
            new Dictionary<string, string>{
                { "Action", "AddUser" },
                { "UserName", "Joe Bloggs" },
                { "Age", "23" } });
        NewUserId = Int.Parse(result["UserId"]);
        

        结束:

        IUserHandler UserHandler = ...;
        
        AddUserResult result = UserHandler.AddUser(new AddUserArgs {
            UserName = "Joe Bloggs",
            Age = 23 });
        NewUserId = result.UserId;
        

        当您可以扩展操作、结果和参数时:

        IUserHandler UserHandler = ...;
        
        AddUserResult2 result = UserHandler.AddUser(new AddUserArgs2 {
            UserName = "Joe Bloggs",
            Age = 23,
            Password = "xyzzy" });
        NewUserId = result.UserId;
        SessionId = result.SessionId;
        
        IUserHandler2 UserHandler2 = UserHandler as IUserHandler2;
        if (UserHandler2 != null)
        {
            LoginUserResult loginResult = UserHandler2.LoginUser(new LoginUserArgs {
                UserId = NewUserId,
                SessionId = SessionId,
                Password = "xyzzy" });
        }
        

        【讨论】:

        • 我猜您使用“Handle”获得的唯一额外灵活性是您甚至不需要在界面上使用特定方法,例如“AddUser”或“LoginUser”。使用句柄,您可以在界面的功能上获得无限的灵活性,但以可用性为代价。
        • 这就是我有 IUserHandler2 示例的原因,它显示您也可以添加新操作。总体而言,它有点冗长,但我更喜欢可发现性,以及关于可用版本的清晰反馈。此外,您可以在连接时检查方法的可用性。
        • 我同意,“handle”方法对于可发现性肯定很糟糕
        【解决方案6】:

        我已经在遗留代码库中看到了“处理程序”类,尤其是对于 Web 服务。但从我所见,这些通常会变成适配器、外观或一些类似的模式,并最终被称为处理程序,因为它正在处理请求。

        【讨论】:

          猜你喜欢
          • 2020-04-09
          • 1970-01-01
          • 2018-08-26
          • 2014-07-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多