Here the resemblance of Command and Servant patterns is discussed. But on the other hand I see that Servant is very similar to Visitor and so much similar that I don't know what is the difference at all? Both serve for other class objects by adding functionality. But command pattern does not add functionality, instead wraps it, right? Please explain where is my confusion.
I'll try to describe my opinion & understanding over the matter and perhaps we can discuss further over it.
Command : As you wrote - It wraps a functionality. Along with the functionality, it also holds the data to be operated upon and the arguments to be passed when the method is applied.
The Execute
method of the command knows how to bring all the pieces together to get the work done.
Therefore, I look at command as an autonomous container of work. Which can be stored & executed later.
Servant : Its a simple pattern which focuses on relieving the Master class (or client class) from its responsibilities by taking them (responsibilities) out in a servant or helper class.
Difference between Command & servant
Time Separation - Commands being an autonomous container, can be stored / queued / sequenced or scheduled and can be executed at a later point of time.
Also, command pattern follows a more black box programming model, since the invoker of the command needs to call only 'Execute
' function.
So a command could be created by one class & invoked by another.
Visitor Pattern and its difference
I'll take an example to explain the difference -
Let's say I have 3 types of mobile devices - iPhone, Android, Windows Mobile.
All these three devices have a Bluetooth radio installed in them.
Let's assume that the blue tooth radio can be from 2 separate OEMs – Intel & Broadcom.
Just to make the example relevant for our discussion, let's also assume that the APIs exposes by Intel radio are different from the ones exposed by Broadcom radio.
This is how my classes look –
Now, I would like to introduce an operation – Switching On the Bluetooth on a mobile device.
Its function signature should like something like this –
void SwitchOnBlueTooth(IMobileDevice mobileDevice, IBlueToothRadio blueToothRadio)
So depending upon the Right type of device and Depending upon the right type of Bluetooth radio, it can be switched on by calling appropriate steps or algorithm.
In principle, it becomes a 3 x 2 matrix, wherein I’m trying to vector the right operation depending upon the right type of objects involved.
A polymorphic behaviour depending upon the type of both the arguments.
So as wiki page says in ‘Motivation’ section A naive way to solve such a problem will suffer from a lot of problems.
Now, I’ll introduce Visitor pattern to this problem. Inspiration comes from the Wikipedia page stating – “In essence, the visitor allows one to add new virtual functions to a family of classes without modifying the classes themselves; instead, one creates a visitor class that implements all of the appropriate specializations of the virtual function. The visitor takes the instance reference as input, and implements the goal through double dispatch.”
Double dispatch is a necessity here due to the 3x2 matrix
Introducing Visitor pattern in code -
I have to make a decision first, which class hierarchy is more stable (less susceptible to change) – Device class hierarchy or the blue tooth class hierarchy. The one more stable will become the visitable classes & the less stable one will become visitor class. For this example, I’ll say the device class is more stable.
Here is the set-up
Here is client code & test code
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);
}
}
Here is the hierarchy of classes
/// <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
{
}
The visitors follow -
/// <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");
}
}
Let me walk through some points of this structure before going to servant pattern–
void SwitchOnBlueTooth(IMobileDevice mobileDevice, IBlueToothRadio blueToothRadio)
, now for double dispatch to work I have changed the signature – instead of IBlueToothRadio
I use IBlueToothVisitor
Now let's look at the same case & let's implement Servant pattern.
Servant pattern is a much simpler pattern, it just aims to take out common functionality from a hierarchy of classes so that it's not duplicated in all of them.
For this let's assume, that all the 3 devices need exactly the same algorithm to switch on Bluetooth. Also, we assume that there is only one type of Radio that exists.
Now either we can write the same algorithm in all the 3 device classes or we can apply the servant pattern as wiki says – “Servant is used for providing some behaviour to a group of classes. Instead of defining that behaviour in each class - or when we cannot factor out this behaviour in the common parent class - it is defined once in the Servant.”
I have pointed out the difference with Red Circles
Here is the client (which is the only place where dispatch is handled) & test code
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);
}
}
The serviced class hierarchy is not that interesting here
/// <summary>
/// Serviced class interface
/// </summary>
interface IMobileDevice
{
}
class iPhone : IMobileDevice
{
}
class Android : IMobileDevice
{
}
class WindowsMobile : IMobileDevice
{
}
here is the servant class & its interface (wiki link doesn't show an interface for it)
/// <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");
}
}
I have not pasted the code for IBlueToothRadio
& BlueToothRadio
since that is not too relevant for discussing servant pattern.
Please let me know if any bit is unclear we can discuss it further.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With