【问题标题】:What does the client do in Command Pattern?客户端在命令模式中做了什么?
【发布时间】:2016-06-12 11:21:44
【问题描述】:

我正在阅读 headfirst 设计模式书。 我观察到客户类似于酒店客户,他们创建了一个order(command) 对象,waitress(invoker) 选择它并调用它的execute() 方法,该方法又调用厨师的cook() method(chef=receiver) 在命令模式类图中,我可以看到客户端与Receiver 以及ConcreteCommand 类相关联。我无法获得示例,因为在现实世界中,客户不应该了解厨师并为他设置说明。另一个问题是,在命令模式类图中,我观察到 Client 未显示与 Invoker 关联,但在附加的 java 程序中,我可以看到 Client 类中的 Invoker 引用。 完全混淆了客户端模块在命令模式中的作用。清除其余 4 个模块。

【问题讨论】:

    标签: java oop object-oriented-analysis


    【解决方案1】:

    阅读:http://www.oodesign.com/command-pattern.html

    客户端创建一个 ConcreteCommand 对象并设置其接收者 [...] 客户端请求执行命令。

    它甚至有示例代码显示客户做了什么

    客户端创建一些买卖股票的订单 (ConcreteCommands)。然后将订单发送给代理(Invoker)。 [...]

    public class Client {
        public static void main(String[] args) {
            StockTrade stock = new StockTrade();
            BuyStockOrder bsc = new BuyStockOrder (stock);
            SellStockOrder ssc = new SellStockOrder (stock);
            Agent agent = new Agent();
    
            agent.placeOrder(bsc); // Buy Shares
            agent.placeOrder(ssc); // Sell Shares
        }
    }
    

    【讨论】:

    • 根据您的示例,StockTrade 是接收方。 BuyStockOrder 是一个具体命令。代理是调用者。客户端类与所有三个相关联但根据上面所附的类图,客户端不知道调用者,即代理。还是一头雾水
    • 所以你很困惑,因为图表没有显示客户端和代理之间的“调用”关联,客户端代码调用placeOrder() 方法?是的,这些图表中似乎确实缺少它。
    • 是的,但我在书中也看到了相同的图表,如果我遗漏了什么会很困惑
    • 你不是。图是。如果它有一条从 Client 到 StockTrade 的线路,则应该存在从 Client 到 Agent 的类似线路。在真实(非示例)代码中,Receiver (StockTrade / Cook) 和 Invoker (Agent / Waiter) 都将在 Client (Customer) 到达现场之前存在,因此它们将通过new以外的方式获得。
    • 同意。我在想的是客户端不会与调用者交谈,该代码可以是调用者或某些业务类的一部分。客户端只负责创建 ConcreteCommand 并在其中设置实际接收者。一旦接线完成,调用者可以稍后执行该命令。在这里,他们想创建一个单独的演示程序,因此将所有东西都吸收到一个程序中。
    【解决方案2】:

    您偶然发现了通过类比、单个具体示例或对象图来演示设计模式的挑战。除了非常简单的模式之外,概念和示例通常不能完美地映射到模式的所有有用实例。

    我强烈建议您选择几个资源来学习任何更复杂的设计模式。每个解释都会有长处和短处,如果您考虑多种观点,您可能会得到更准确的图片。互联网上有大量免费资源,因此您可能不需要购买额外的书籍(最终,the original Design Patterns book 除外,仅供参考)。

    图中不清楚的是ClientInvokerReceiver 是抽象概念,并没有一个始终适用于每种情况的单一形式。在命令模式的任何特定实现中,这些角色中的大多数都会出现(可能除了Receiver - 该命令可能是自包含的)。您甚至可以指出映射到每个角色的特定代码位,但它在每个应用程序中的映射方式都不同。它甚至可以在同一个应用程序的不同部分进行不同的映射。

    您分享的图表的某些部分我有问题,因为它们并不总是正确的。 Client 可能无法直接访问甚至不知道ReceiverClient 也可能不知道特定的 ConcreteCommand 对象。 Client 可能知道如何请求命令的实例,并且它可能知道一些有助于选择正确命令的信息。但是,在某些情况下,客户端可能不知道执行了哪个ConcreteCommand 对象,尤其是当您将命令模式与the AbstractFactory pattern 结合使用时。

    在现实世界中,客户不应该知道厨师并为他设置说明

    当您将类比和模型与现实进行严格比较时,它们往往会崩溃或变得混乱。最好尝试弄清楚模型试图完成什么,以及模型试图解释的对现实的可能解释。

    另外,并不是所有的模型/类比都好 :) 有时它们实际上并没有完成工作。

    我观察到客户端未显示与 Invoker 关联

    这在该模式的某些实现中是完全有效的。最终调用execute() 的代码可能与能够接受操作的代码不同。

    该图可能显示一个盒子,但在餐厅类比中,服务员、厨师、服务员、主持人、收银员等都是Invoker 角色的一部分。

    图表的问题是客户端最终必须将命令传递给调用者。调用者本身可能有办法完成此操作,或者两者之间可能存在某种系统(如命令队列)。无论哪种方式,在他们的解释中,调用者角色都处理这两种事情,因此客户端必须知道调用者。

    最后:

    客户端在命令模式中做了什么?

    • Client 负责知道它想要执行命令
    • Client 负责了解如何选择完成哪个命令并获取它的实例(即使客户端将 ConcreteCommand 的实际构造委托给系统的其他部分)
    • Client 负责知道如何传递命令以便最终调用它(将其传递给 Invoker 角色中的某个对象,即使该命令最终传递给其他对象实际调用execute())
    • Client 负责将命令实际传递给Invoker(无论是直接传递,还是先传递给系统的某个中间部分)

    【讨论】:

      【解决方案3】:

      因此,客户端的概念与服务器的概念相反。 (为了得到餐厅的隐喻一分钟)。服务器是集中式应用程序,客户端是呈现在用户机器上的界面。客户端机器或 GUI 信号会直接通过接收器(中间人)或您的程序来使事情发生。

      我希望这能让事情更清楚一点。

      【讨论】:

        猜你喜欢
        • 2016-08-07
        • 2020-08-30
        • 2010-10-27
        • 2017-04-30
        • 1970-01-01
        • 2016-11-17
        • 1970-01-01
        • 2012-07-10
        • 1970-01-01
        相关资源
        最近更新 更多