这里讨论了命令模式和服务模式的相似之处。但是另一方面,我发现服务模式与访问者模式非常相似,甚至相似到我完全不知道它们的区别在哪里?两者都通过添加功能为其他类对象提供服务。但是命令模式不会添加功能,而是将其包装起来,对吗?请解释一下我的困惑所在。
这里讨论了命令模式和服务模式的相似之处。但是另一方面,我发现服务模式与访问者模式非常相似,甚至相似到我完全不知道它们的区别在哪里?两者都通过添加功能为其他类对象提供服务。但是命令模式不会添加功能,而是将其包装起来,对吗?请解释一下我的困惑所在。
void SwitchOnBlueTooth(IMobileDevice mobileDevice, IBlueToothRadio blueToothRadio)
因此,根据正确类型的设备和正确类型的蓝牙收发器,可以通过调用适当的步骤或算法来打开它。
原则上,它变成了一个3×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);
}
}
/// <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
{
}
/// <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");
}
}
在讲解仆人模式之前,让我简单介绍一下这个结构:
void SwitchOnBlueTooth(IMobileDevice mobileDevice, IBlueToothRadio blueToothRadio)
,现在为了让双重分派工作,我更改了签名-使用 IBlueToothVisitor
替代了 IBlueToothRadio
。这是处理调度的唯一位置——客户端和测试代码。
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);
}
}
在这里,服务类层次结构并不那么有趣。
/// <summary>
/// Serviced class interface
/// </summary>
interface IMobileDevice
{
}
class iPhone : IMobileDevice
{
}
class Android : IMobileDevice
{
}
class WindowsMobile : IMobileDevice
{
}
/// <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");
}
}
我没有粘贴 IBlueToothRadio
和 BlueToothRadio
的代码,因为这对于讨论服务模式并不太相关。
如果有任何不清楚的地方,请告诉我,我们可以进一步讨论。