访客vs仆人vs命令模式

Nar*_*rek 4 design-patterns visitor-pattern command-pattern

这里讨论了Command和Servant模式的相似之处.但另一方面,我看到仆人与访客非常相似,而且非常相似,我不知道有什么区别?两者都通过添加功能为其他类对象服务.但命令模式不会添加功能,而是包装它,对吧?请解释一下我的困惑在哪里.

Kap*_*oor 12

我将尝试描述我对此事的看法和理解,也许我们可以进一步讨论.

命令:正如你所写 - 它包含了一个功能.除了功能之外,它还包含要操作的数据以及应用该方法时要传递的参数.

Execute命令的方法知道如何将所有部分组合在一起以完成工作.

因此,我将命令看作是一个自主的工作容器.哪些可以存储和执行.

Servant:它是一个简单的模式,专注于通过在服务员或帮助者类中承担(责任)来减轻Master类(或客户端类)的职责.

命令与仆人之间的区别

时间分离 - 作为自治容器的命令可以存储/排队/排序或调度,并且可以在稍后的时间点执行.
此外,命令模式遵循更黑的框编程模型,因为命令的调用者只需要调用' Execute'函数.

因此,命令可以由一个类创建并由另一个类调用.

访客模式及其差异

我会举一个例子来解释其中的区别 -

假设我有3种类型的移动设备 - iPhone,Android,Windows Mobile.

所有这三个设备都安装了蓝牙无线电.

我们假设蓝牙收音机可以来自两个独立的原始设备制造商 - 英特尔和Broadcom.

为了使示例与我们的讨论相关,我们还假设英特尔无线电公开的API与Broadcom无线电公开的API不同.

这就是我的课程外观 -

在此输入图像描述

在此输入图像描述

现在,我想介绍一项操作 - 在移动设备上打开蓝牙.

它的功能签名应该像这样 -

 void SwitchOnBlueTooth(IMobileDevice mobileDevice, IBlueToothRadio blueToothRadio)
Run Code Online (Sandbox Code Playgroud)

所以根据权利类型的设备,并根据不同的权类型蓝牙无线电的,它可以通过接通调用适当的步骤或算法.

原则上,它变成一个3 x 2矩阵,其中我试图根据所涉及的对象的正确类型来引导正确的操作.

多态行为取决于两个参数的类型.在此输入图像描述

因此,维基页面在"动机"部分中说,解决此类问题的天真方法会遇到很多问题.

现在,我将介绍访问者模式到这个问题.灵感来自维基百科页面,指出 - "实质上,访问者允许一个人在不修改类本身的情况下向一个类族添加新的虚函数; 相反,我们创建了一个访问者类,它实现了虚函数的所有适当的特化.访问者将实例引用作为输入,并通过双重调度实现目标."

由于3x2矩阵,双重调度是必要的

在代码中引入访客模式 -

我必须首先做出决定,哪个类层次结构更稳定(更不容易改变) - 设备类层次结构或蓝牙类层次结构.一个更稳定的将成为可访问的类和不太稳定的将成为访客类.对于这个例子,我会说设备类更稳定.

这是设置

在此输入图像描述

这是客户端代码和测试代码

 class Client
  {
      public void SwitchOnBlueTooth(IMobileDevice mobileDevice, IBlueToothVisitor blueToothRadio) 
      {
          mobileDevice.TurnOn(blueToothRadio);        
      }
  }


 [TestClass]
public class VisitorPattern
{

    Client mClient = new Client();

    [TestMethod]
    public void AndroidOverBroadCom()
    {
        IMobileDevice device = new Android();
        IBlueToothVisitor btVisitor = new BroadComBlueToothVisitor();

        mClient.SwitchOnBlueTooth(device, btVisitor);
    }

    [TestMethod]
    public void AndroidOverIntel()
    {
        IMobileDevice device = new Android();
        IBlueToothVisitor btVisitor = new IntelBlueToothVisitor();

        mClient.SwitchOnBlueTooth(device, btVisitor);
    }

    [TestMethod]
    public void iPhoneOverBroadCom()
    {
        IMobileDevice device = new iPhone();
        IBlueToothVisitor btVisitor = new BroadComBlueToothVisitor();

        mClient.SwitchOnBlueTooth(device, btVisitor);
    }

    [TestMethod]
    public void iPhoneOverIntel()
    {
        IMobileDevice device = new iPhone();
        IBlueToothVisitor btVisitor = new IntelBlueToothVisitor();

        mClient.SwitchOnBlueTooth(device, btVisitor);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是类的层次结构

     /// <summary>
        /// Visitable class interface 
        /// </summary>
       interface IMobileDevice
        {
           /// <summary>
           /// It is the 'Accept' method of visitable class
           /// </summary>
            /// <param name="blueToothVisitor">Visitor Visiting the class</param>
           void TurnOn(IBlueToothVisitor blueToothVisitor);
        }

       class iPhone : IMobileDevice
       {
           public void TurnOn(IBlueToothVisitor blueToothVisitor)
           {
               blueToothVisitor.SwitchOn(this);
           }
       }

       class Android : IMobileDevice
       {
           public void TurnOn(IBlueToothVisitor blueToothVisitor)
           {
               blueToothVisitor.SwitchOn(this);
           }
       }

       class WindowsMobile : IMobileDevice
       {
           public void TurnOn(IBlueToothVisitor blueToothVisitor)
           {
               blueToothVisitor.SwitchOn(this);
           }
       }

        interface IBlueToothRadio
        {

        }

        class BroadComBlueToothRadio : IBlueToothRadio
        {

        }

        class IntelBlueToothRadio : IBlueToothRadio
        {

        }
Run Code Online (Sandbox Code Playgroud)

访客关注 -

/// <summary>
/// Wiki Page - The Visitor pattern encodes a logical operation on the whole hierarchy into a single class containing one method per type. 
/// </summary>
interface IBlueToothVisitor
{
    void SwitchOn(iPhone device);
    void SwitchOn(WindowsMobile device);
    void SwitchOn(Android device);
}


class IntelBlueToothVisitor : IBlueToothVisitor
{
    IBlueToothRadio intelRadio = new IntelBlueToothRadio();

    public void SwitchOn(iPhone device)
    {
        Console.WriteLine("Swithing On intel radio on iPhone");
    }

    public void SwitchOn(WindowsMobile device)
    {
        Console.WriteLine("Swithing On intel radio on Windows Mobile");
    }

    public void SwitchOn(Android device)
    {
        Console.WriteLine("Swithing On intel radio on Android");
    }
}

class BroadComBlueToothVisitor : IBlueToothVisitor
{
    IBlueToothRadio broadCom = new BroadComBlueToothRadio();

    public void SwitchOn(iPhone device)
    {
        Console.WriteLine("Swithing On BroadCom radio on iPhone");
    }

    public void SwitchOn(WindowsMobile device)
    {
        Console.WriteLine("Swithing On BroadCom radio on Windows Mobile");
    }

    public void SwitchOn(Android device)
    {
        Console.WriteLine("Swithing On BroadCom radio on Android");
    }
}
Run Code Online (Sandbox Code Playgroud)

在进入仆人模式之前,让我逐步探讨这个结构的一些要点 -

  1. 我有2个蓝牙访问者,其中包含在每种类型的移动设备上打开蓝牙的算法
  2. 我一直保持BluetoothVistor和BluetoothRadio的独立性,以便坚持访客的理念 - "在不修改类本身的情况下添加操作".也许其他人想将它合并到BluetoothRadio类本身.
  3. 每个访问者定义了3个功能 - 每个类型的移动设备一个.(这与Servant模式有一个很大的不同 - Servant模式应该只为所有服务类提供一个算法.)
  4. 此外,由于存在6种算法变体(取决于对象的类型),因此需要双重调度.在服务方式模式中,我们只讨论算法的一个变体.
  5. 正如我上面写的那样,我原来的要求就是拥有这样的功能 - void SwitchOnBlueTooth(IMobileDevice mobileDevice, IBlueToothRadio blueToothRadio)现在为了双重调度工作,我改变了签名 - 而不是IBlueToothRadio我使用IBlueToothVisitor

现在让我们看看相同的情况,让我们实现Servant模式.

Servant模式是一个更简单的模式,它只是旨在从类的层次结构中取出共同的功能,以便它不会在所有类中重复.

为此,我们假设所有3个设备都需要完全相同的算法才能打开蓝牙.此外,我们假设只存在一种类型的无线电.

现在要么我们可以在所有3个设备类中编写相同的算法,要么我们可以应用servant模式,因为wiki说 - "Servant用于为一组类提供一些行为.不是在每个类中定义该行为 - 或者当我们不能在公共父类中分解出这种行为时 - 它在Servant中定义一次.

在此输入图像描述

我已经指出了与红圈的区别

  1. 不需要双重调度,客户端可以直接调用服务类的服务方
  2. 所有3个设备的单一算法

这是客户端(这是处理调度的唯一地方)和测试代码

class Client
 {
    public void SwitchOnBlueTooth(IMobileDevice mobileDevice,    IBlueToothServant blueToothRadio)
    {
        //there is just one BT servant & all the serviced types get the same service (No There is no specificity). 
        // Wiki page - User knows the servant (in which case he doesn’t need to know the serviced classes) and sends messages with his requests to the servant instances, passing the serviced objects as parameters.
        blueToothRadio.SwitchOn(mobileDevice);
    }
}


[TestClass]
public class ServantPattern
{

    Client mClient = new Client();

    [TestMethod]
    public void AndroidBlueToothOn()
    {
        IMobileDevice device = new Android();
        IBlueToothServant btServant = new BlueToothServant();

        mClient.SwitchOnBlueTooth(device, btServant);
    }

    [TestMethod]
    public void iPhoneOverBroadCom()
    {
        IMobileDevice device = new iPhone();
        IBlueToothServant btServant = new BlueToothServant();

        mClient.SwitchOnBlueTooth(device, btServant);
    }

    [TestMethod]
    public void WMBlueToothOn()
    {
        IMobileDevice device = new WindowsMobile();
        IBlueToothServant btServant = new BlueToothServant();

        mClient.SwitchOnBlueTooth(device, btServant);
    }
}
Run Code Online (Sandbox Code Playgroud)

服务类层次结构在这里并不那么有趣

/// <summary>
/// Serviced class interface 
/// </summary>
interface IMobileDevice
{

}

class iPhone : IMobileDevice
{

}

class Android : IMobileDevice
{
}

class WindowsMobile : IMobileDevice
{
}
Run Code Online (Sandbox Code Playgroud)

这里是servant类及其接口(wiki链接没有显示它的接口)

 /// <summary>
 /// The sevant interface
 /// </summary>
 /// <remarks>Not present in Wiki article but I have added so its easy to          mock it</remarks>
 interface IBlueToothServant
 {
     void SwitchOn(IMobileDevice device);
 }


class BlueToothServant : IBlueToothServant
{
    IBlueToothRadio intelRadio = new BlueToothRadio();

    public void SwitchOn(IMobileDevice device)
    {
        Console.WriteLine("Switching On blue tooth radio on IMobileDevice");
    }

}
Run Code Online (Sandbox Code Playgroud)

我还没有粘贴代码IBlueToothRadio&BlueToothRadio因为这是不是讨论仆人模式也有关.

如果不清楚我们可以进一步讨论,请告诉我.