In software engineering, the servant pattern defines an object used to offer some functionality to a group of classes without defining that functionality in each of them. A Servant is a class whose instance provides methods that take care of a desired service, while objects for which the servant does something, are taken as parameters.
Servant is used for providing some behavior to a group of classes. Instead of defining that behavior in each class - or when we cannot factor out this behavior in the common parent class - it is defined once in the Servant. For example: we have a few classes representing geometric objects. We can draw these objects on some canvas. When we need to provide a “move” method for these objects we could implement this method in each class, or we can define an interface they implement and then offer the “move” functionality in a servant. An interface is defined to ensure that serviced classes have methods, that servant needs to provide desired behavior. If we continue in our example, we define an Interface “Movable” specifying that every class implementing this interface needs to implement method “getPosition” and “setPosition”. The first method gets the position of an object on a canvas and second one sets the position of an object and draws it on a canvas. Then we define a servant class “MoveServant”, which has two methods “moveTo” and moveBy. The Servant class can now be used to move every object which implements the Movable. Thus the “moving” code appears in only one class which respects the “Separation of Concerns” rule.
User knows the servant and sends messages with his requests to the servant instances, passing the serviced objects as parameters.
The serviced classes don’t know about servant, but they implement the “IServiced” interface. The user class just calls the method of servant and passes serviced objects as parameters. This situation is shown on figure 1.
Serviced instances know the servant and the user sends them messages with his requests. The serviced instances then send messages to the instances of servant, asking for service.
On figure 2 is shown opposite situation, where user don’t know about servant class and calls directly serviced classes. Serviced classes then asks servant themselves to achieve desired functionality.
How to implement Servant
Analyze what behavior servant should take care of. State what methods servant will define and what these methods will need from serviced parameter. By other words, what serviced instance must provide, so that servants methods can achieve their goals.
Analyze what abilities serviced classes must have, so they can be properly serviced.
We define an interface, which will enforce implementation of declared methods.
Define an interface specifying requested behavior of serviced objects. If some instance wants to be served by servant, it must implement this interface.
Define specified servant.
Implement defined interface with serviced classes.
Example
This simple example shows the situation described above. This example is only illustrative and will not offer any actual drawing of geometric objects, nor specification of what they look like. // Servant class, offering its functionality to classes implementing // Movable Interface public class MoveServant // Interface specifying what serviced classes needs to implement, to be // serviced by servant. public interface Movable // One of geometric classes public class Triangle implements Movable // One of geometric classes public class Ellipse implements Movable // One of geometric classes public class Rectangle implements Movable // Just a very simple container class for position. public class Position
Design patterns Command and Servant are very similar and implementations of them are often virtually the same. The difference between them is the approach to the problem.
For the Servant pattern we have some objects to which we want to offer some functionality. We create a class whose instances offer that functionality and which defines an interface that serviced objects must implement. Serviced instances are then passed as parameters to the servant.
For the Command pattern we have some objects that we want to modify with some functionality. So, we define an interface which commands which desired functionality must be implemented. Instances of those commands are then passed to original objects as parameters of their methods.
Even though design patterns Command and Servant are similar it doesn’t mean it’s always like that. There are a number of situations where use of design pattern Command doesn’t relate to the design pattern Servant. In these situations we usually need to pass to called methods just a reference to another method, which it will need in accomplishing its goal. Since we can’t pass references to methods in many languages, we have to pass an object implementing an interface which declares the signature of passed method.