Strategy pattern

Last updated

In computer programming, the strategy pattern (also known as the policy pattern) is a behavioral software design pattern that enables selecting an algorithm at runtime. Instead of implementing a single algorithm directly, code receives runtime instructions as to which in a family of algorithms to use. [1]

Contents

Strategy lets the algorithm vary independently from clients that use it. [2] Strategy is one of the patterns included in the influential book Design Patterns by Gamma et al. [3] that popularized the concept of using design patterns to describe how to design flexible and reusable object-oriented software. Deferring the decision about which algorithm to use until runtime allows the calling code to be more flexible and reusable.

For instance, a class that performs validation on incoming data may use the strategy pattern to select a validation algorithm depending on the type of data, the source of the data, user choice, or other discriminating factors. These factors are not known until runtime and may require radically different validation to be performed. The validation algorithms (strategies), encapsulated separately from the validating object, may be used by other validating objects in different areas of the system (or even different systems) without code duplication.

Typically, the strategy pattern stores a reference to code in a data structure and retrieves it. This can be achieved by mechanisms such as the native function pointer, the first-class function, classes or class instances in object-oriented programming languages, or accessing the language implementation's internal storage of code via reflection.

Structure

UML class and sequence diagram

A sample UML class and sequence diagram for the Strategy design pattern. W3sDesign Strategy Design Pattern UML.jpg
A sample UML class and sequence diagram for the Strategy design pattern.

In the above UML class diagram, the Context class does not implement an algorithm directly. Instead, Context refers to the Strategy interface for performing an algorithm (strategy.algorithm()), which makes Context independent of how an algorithm is implemented. The Strategy1 and Strategy2 classes implement the Strategy interface, that is, implement (encapsulate) an algorithm.
The UML sequence diagram shows the runtime interactions: The Context object delegates an algorithm to different Strategy objects. First, Context calls algorithm() on a Strategy1 object, which performs the algorithm and returns the result to Context. Thereafter, Context changes its strategy and calls algorithm() on a Strategy2 object, which performs the algorithm and returns the result to Context.

Class diagram

Strategy Pattern in UML Strategy Pattern in UML.png
Strategy Pattern in UML

[5]

Strategy pattern in LePUS3 (legend) Strategy pattern in LePUS3.gif
Strategy pattern in LePUS3 (legend)


Strategy and open/closed principle

Accelerate and brake behaviors must be declared in each new car model. StrategyPattern IBrakeBehavior.svg
Accelerate and brake behaviors must be declared in each new car model.

According to the strategy pattern, the behaviors of a class should not be inherited. Instead, they should be encapsulated using interfaces. This is compatible with the open/closed principle (OCP), which proposes that classes should be open for extension but closed for modification.

As an example, consider a car class. Two possible functionalities for car are brake and accelerate. Since accelerate and brake behaviors change frequently between models, a common approach is to implement these behaviors in subclasses. This approach has significant drawbacks; accelerate and brake behaviors must be declared in each new car model. The work of managing these behaviors increases greatly as the number of models increases, and requires code to be duplicated across models. Additionally, it is not easy to determine the exact nature of the behavior for each model without investigating the code in each.

The strategy pattern uses composition instead of inheritance. In the strategy pattern, behaviors are defined as separate interfaces and specific classes that implement these interfaces. This allows better decoupling between the behavior and the class that uses the behavior. The behavior can be changed without breaking the classes that use it, and the classes can switch between behaviors by changing the specific implementation used without requiring any significant code changes. Behaviors can also be changed at runtime as well as at design-time. For instance, a car object's brake behavior can be changed from BrakeWithABS() to Brake() by changing the brakeBehavior member to:

brakeBehavior=newBrake();
/* Encapsulated family of Algorithms * Interface and its implementations */publicinterfaceIBrakeBehavior{publicvoidbrake();}publicclassBrakeWithABSimplementsIBrakeBehavior{publicvoidbrake(){System.out.println("Brake with ABS applied");}}publicclassBrakeimplementsIBrakeBehavior{publicvoidbrake(){System.out.println("Simple Brake applied");}}/* Client that can use the algorithms above interchangeably */publicabstractclassCar{privateIBrakeBehaviorbrakeBehavior;publicCar(IBrakeBehaviorbrakeBehavior){this.brakeBehavior=brakeBehavior;}publicvoidapplyBrake(){brakeBehavior.brake();}publicvoidsetBrakeBehavior(IBrakeBehaviorbrakeType){this.brakeBehavior=brakeType;}}/* Client 1 uses one algorithm (Brake) in the constructor */publicclassSedanextendsCar{publicSedan(){super(newBrake());}}/* Client 2 uses another algorithm (BrakeWithABS) in the constructor */publicclassSUVextendsCar{publicSUV(){super(newBrakeWithABS());}}/* Using the Car example */publicclassCarExample{publicstaticvoidmain(finalString[]arguments){CarsedanCar=newSedan();sedanCar.applyBrake();// This will invoke class "Brake"CarsuvCar=newSUV();suvCar.applyBrake();// This will invoke class "BrakeWithABS"// set brake behavior dynamicallysuvCar.setBrakeBehavior(newBrake());suvCar.applyBrake();// This will invoke class "Brake"}}

See also

Related Research Articles

A visitor pattern is a software design pattern that separates the algorithm from the object structure. Because of this separation new operations can be added to existing object structures without modifying the structures. It is one way to follow the open/closed principle in object-oriented programming and software engineering.

<i>Design Patterns</i> 1994 software engineering book

Design Patterns: Elements of Reusable Object-Oriented Software (1994) is a software engineering book describing software design patterns. The book was written by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, with a foreword by Grady Booch. The book is divided into two parts, with the first two chapters exploring the capabilities and pitfalls of object-oriented programming, and the remaining chapters describing 23 classic software design patterns. The book includes examples in C++ and Smalltalk.

<span class="mw-page-title-main">Abstract factory pattern</span> Software design pattern

The abstract factory pattern in software engineering is a design pattern that provides a way to create families of related objects without imposing their concrete classes, by encapsulating a group of individual factories that have a common theme without specifying their concrete classes. According to this pattern, a client software component creates a concrete implementation of the abstract factory and then uses the generic interface of the factory to create the concrete objects that are part of the family. The client does not know which concrete objects it receives from each of these internal factories, as it uses only the generic interfaces of their products. This pattern separates the details of implementation of a set of objects from their general usage and relies on object composition, as object creation is implemented in methods exposed in the factory interface.

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.

<span class="mw-page-title-main">Flyweight pattern</span> Software design pattern for objects

In computer programming, the flyweight software design pattern refers to an object that minimizes memory usage by sharing some of its data with other similar objects. The flyweight pattern is one of twenty-three well-known GoF design patterns. These patterns promote flexible object-oriented software design, which is easier to implement, change, test, and reuse.

The builder pattern is a design pattern designed to provide a flexible solution to various object creation problems in object-oriented programming. The intent of the builder design pattern is to separate the construction of a complex object from its representation. It is one of the Gang of Four design patterns.

In object oriented programming, the factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created. This is done by creating objects by calling a factory method—either specified in an interface and implemented by child classes, or implemented in a base class and optionally overridden by derived classes—rather than by calling a constructor.

The prototype pattern is a creational design pattern in software development. It is used when the types of objects to create is determined by a prototypical instance, which is cloned to produce new objects. This pattern is used to avoid subclasses of an object creator in the client application, like the factory method pattern does, and to avoid the inherent cost of creating a new object in the standard way when it is prohibitively expensive for a given application.

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 instances of 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 as well as to the Open-Closed Principle, by allowing the functionality of a class to be extended without being modified. 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 command pattern is a behavioral design pattern in which an object is used to encapsulate all information needed to perform an action or trigger an event at a later time. This information includes the method name, the object that owns the method and values for the method parameters.

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.

In software engineering, the mediator pattern defines an object that encapsulates how a set of objects interact. This pattern is considered to be a behavioral pattern due to the way it can alter the program's running behavior.

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 object-oriented programming, the template method is one of the behavioral design patterns identified by Gamma et al. in the book Design Patterns. The template method is a method in a superclass, usually an abstract superclass, and defines the skeleton of an operation in terms of a number of high-level steps. These steps are themselves implemented by additional helper methods in the same class as the template method.

<span class="mw-page-title-main">Dependency injection</span> Software programming technique

In software engineering, dependency injection is a programming technique in which an object or function receives other objects or functions that it requires, as opposed to creating them internally. Dependency injection aims to separate the concerns of constructing objects and using them, leading to loosely coupled programs. The pattern ensures that an object or function which wants to use a given service should not have to know how to construct those services. Instead, the receiving 'client' is provided with its dependencies by external code, which it is not aware of. Dependency injection makes implicit dependencies explicit and helps solve the following problems:

In the Java computer programming language, an annotation is a form of syntactic metadata that can be added to Java source code. Classes, methods, variables, parameters and Java packages may be annotated. Like Javadoc tags, Java annotations can be read from source files. Unlike Javadoc tags, Java annotations can also be embedded in and read from Java class files generated by the Java compiler. This allows annotations to be retained by the Java virtual machine at run-time and read via reflection. It is possible to create meta-annotations out of the existing ones in Java.

<span class="mw-page-title-main">Composition over inheritance</span> Software design pattern

Composition over inheritance in object-oriented programming (OOP) is the principle that classes should favor polymorphic behavior and code reuse by their composition over inheritance from a base or parent class. Ideally all reuse can be achieved by assembling existing components, but in practice inheritance is often needed to make new ones. Therefore inheritance and object composition typically work hand-in-hand, as discussed in the book Design Patterns (1994).

In object-oriented programming, forwarding means that using a member of an object results in actually using the corresponding member of a different object: the use is forwarded to another object. Forwarding is used in a number of design patterns, where some members are forwarded to another object, while others are handled by the directly used object. The forwarding object is frequently called a wrapper object, and explicit forwarding members are called wrapper functions.

References

  1. "The Strategy design pattern - Problem, Solution, and Applicability". w3sDesign.com. Retrieved 2017-08-12.
  2. Eric Freeman, Elisabeth Freeman, Kathy Sierra and Bert Bates, Head First Design Patterns, First Edition, Chapter 1, Page 24, O'Reilly Media, Inc, 2004. ISBN   978-0-596-00712-6
  3. Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (1994). Design Patterns: Elements of Reusable Object-Oriented Software . Addison Wesley. pp.  315ff. ISBN   0-201-63361-2.{{cite book}}: CS1 maint: multiple names: authors list (link)
  4. "The Strategy design pattern - Structure and Collaboration". w3sDesign.com. Retrieved 2017-08-12.
  5. "Design Patterns Quick Reference – McDonaldLand".