Servant (design pattern)

Last updated

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 (or even just class) provides methods that take care of a desired service, while objects for which (or with whom) the servant does something, are taken as parameters.

Contents

Description and simple example

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 (rectangle, ellipse, and triangle). 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(Movable movedObject, Position where)” and moveBy(Movable movedObject, int dx, int dy). 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.

Two ways of implementation

There are two ways to implement this design pattern.

Figure 1: User uses servant to achieve some functionality and passes the serviced objects as parameters. DesignPatternServantFigure1.png
Figure 1: User uses servant to achieve some functionality and passes the serviced objects as parameters.
  1. 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.
  2. The serviced classes (geometric objects from our example) 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.
Figure 2: User requests operations from serviced instances, which then asks servant to do it for them. DesignPatternServantFigure2.png
Figure 2: User requests operations from serviced instances, which then asks servant to do it for them.
  1. Serviced instances know the servant and the user sends them messages with his requests (in which case she doesn’t have to know the servant). The serviced instances then send messages to the instances of servant, asking for service.
  2. 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

  1. 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.
  2. Analyze what abilities serviced classes must have, so they can be properly serviced.
  3. We define an interface, which will enforce implementation of declared methods.
  4. Define an interface specifying requested behavior of serviced objects. If some instance wants to be served by servant, it must implement this interface.
  5. Define (or acquire somehow) specified servant (his class).
  6. Implement defined interface with serviced classes.

Example

This simple Java 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 InterfacepublicclassMoveServant{// Method, which will move Movable implementing class to position wherepublicvoidmoveTo(Movableserviced,Positionwhere){// Do some other stuff to ensure it moves smoothly and nicely, this is// the place to offer the functionalityserviced.setPosition(where);}// Method, which will move Movable implementing class by dx and dypublicvoidmoveBy(Movableserviced,intdx,intdy){// this is the place to offer the functionalitydx+=serviced.getPosition().xPosition;dy+=serviced.getPosition().yPosition;serviced.setPosition(newPosition(dx,dy));}}// Interface specifying what serviced classes needs to implement, to be// serviced by servant.publicinterfaceMovable{publicvoidsetPosition(Positionp);publicPositiongetPosition();}// One of geometric classespublicclassTriangleimplementsMovable{// Position of the geometric object on some canvasprivatePositionp;// Method, which sets position of geometric objectpublicvoidsetPosition(Positionp){this.p=p;}// Method, which returns position of geometric objectpublicPositiongetPosition(){returnthis.p;}}// One of geometric classespublicclassEllipseimplementsMovable{// Position of the geometric object on some canvasprivatePositionp;// Method, which sets position of geometric objectpublicvoidsetPosition(Positionp){this.p=p;}// Method, which returns position of geometric objectpublicPositiongetPosition(){returnthis.p;}}// One of geometric classespublicclassRectangleimplementsMovable{// Position of the geometric object on some canvasprivatePositionp;// Method, which sets position of geometric objectpublicvoidsetPosition(Positionp){this.p=p;}// Method, which returns position of geometric objectpublicPositiongetPosition(){returnthis.p;}}// Just a very simple container class for position.publicclassPosition{publicintxPosition;publicintyPosition;publicPosition(intdx,intdy){xPosition=dx;yPosition=dy;}}

Similar design pattern: Command

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.

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.

See also

Resources

Pecinovský, Rudolf; Jarmila Pavlíčková; Luboš Pavlíček (June 2006). Let's Modify the Objects First Approach into Design Patterns First (PDF). Eleventh Annual Conference on Innovation and Technology in Computer Science Education, University of Bologna.

Related Research Articles

In object-oriented programming and software engineering, the visitor design pattern is a way of separating an algorithm from an object structure on which it operates. A practical result of this separation is the ability to add new operations to existing object structures without modifying the structures. It is one way to follow the open/closed principle.

In programming languages, a closure, also lexical closure or function closure, is a technique for implementing lexically scoped name binding in a language with first-class functions. Operationally, a closure is a record storing a function together with an environment. The environment is a mapping associating each free variable of the function with the value or reference to which the name was bound when the closure was created. Unlike a plain function, a closure allows the function to access those captured variables through the closure's copies of their values or references, even when the function is invoked outside their scope.

In software engineering, the adapter pattern is a software design pattern that allows the interface of an existing class to be used as another interface. It is often used to make existing classes work with others without modifying their source code.

The facade pattern is a software-design pattern commonly used in object-oriented programming. Analogous to a facade in architecture, a facade is an object that serves as a front-facing interface masking more complex underlying or structural code. A facade can:

The bridge pattern is a design pattern used in software engineering that is meant to "decouple an abstraction from its implementation so that the two can vary independently", introduced by the Gang of Four. The bridge uses encapsulation, aggregation, and can use inheritance to separate responsibilities into different classes.

Singleton pattern

In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to one "single" instance. This is useful when exactly one object is needed to coordinate actions across the system. The term comes from the mathematical concept of a singleton.

In object-oriented programming, the decorator pattern is a design pattern that allows behavior to be added to an individual object, dynamically, without affecting the behavior of other objects from the same class. The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern. Decorator use can be more efficient than subclassing, because an object's behavior can be augmented without defining an entirely new object.

In object-oriented programming, the iterator pattern is a design pattern in which an iterator is used to traverse a container and access the container's elements. The iterator pattern decouples algorithms from containers; in some cases, algorithms are necessarily container-specific and thus cannot be decoupled.

The state pattern is a behavioral software design pattern that allows an object to alter its behavior when its internal state changes. This pattern is close to the concept of finite-state machines. The state pattern can be interpreted as a strategy pattern, which is able to switch a strategy through invocations of methods defined in the pattern's interface.

In computer programming, the strategy pattern is a behavioral software design pattern that enables selecting an algorithm at runtime. Instead of implementing a single algorithm directly, code receives run-time instructions as to which in a family of algorithms to use.

A method in object-oriented programming (OOP) is a procedure associated with a message and an object. An object consists of data and behavior; these comprise an interface, which specifies how the object may be utilized by any of its various consumers.

In object-oriented programming, in languages such as C++, and Object Pascal, a virtual function or virtual method is an inheritable and overridable function or method for which dynamic dispatch is facilitated. This concept is an important part of the (runtime) polymorphism portion of object-oriented programming (OOP). In short, a virtual function defines a target function to be executed, but the target might not be known at compile time.

Java syntax

The syntax of Java refers to the set of rules defining how a Java program is written and interpreted.

In software engineering, dependency injection is a technique in which an object receives other objects that it depends on. These other objects are called dependencies. In the typical "using" relationship the receiving object is called a client and the passed object is called a service. The code that passes the service to the client can be many kinds of things and is called the injector. Instead of the client specifying which service it will use, the injector tells the client what service to use. The "injection" refers to the passing of a dependency into the object that would use it.

In software engineering, a fluent interface is an object-oriented API whose design relies extensively on method chaining. Its goal is to increase code legibility by creating a domain-specific language (DSL). The term was coined in 2005 by Eric Evans and Martin Fowler.

This article describes the syntax of the C# programming language. The features described are compatible with .NET Framework and Mono.

Composition over inheritance Software design pattern

Composition over inheritance in object-oriented programming (OOP) is the principle that classes should achieve polymorphic behavior and code reuse by their composition rather than inheritance from a base or parent class. This is an often-stated principle of OOP, such as in the influential book Design Patterns (1994).

In object-oriented programming, "immutable interface" is a pattern for designing an immutable object. The immutable interface pattern involves defining a type which does not provide any methods which mutate state. Objects which are referenced by that type are not seen to have any mutable state, and appear immutable.

Objective-C is a general-purpose, object-oriented programming language that adds Smalltalk-style messaging to the C programming language. It is one of two main programming languages supported by Apple for macOS, iOS, and their respective application programming interfaces (APIs), Cocoa and Cocoa Touch. It was the singular main language until the introduction of Swift in 2014.

In software engineering, the Twin pattern is a software design pattern that allows developers to model multiple inheritance in programming languages that do not support multiple inheritance. This pattern avoids many of the problems with multiple inheritance.