Exploring Behavioral Design Patterns: Strategy & Template Methods

In this blog, we explore behavioral design patterns, with an emphasis on Strategy & Template patterns. The blog highlights the significance of behavioral design patterns in crafting code that is flexible, maintainable & efficient.

GraphQL has a role beyond API Query Language- being the backbone of application Integration
background Coditation

Exploring Behavioral Design Patterns: Strategy & Template Methods

In our last blog, we implemented and discussed creational design patterns. In this blog, we will be exploring behavioral design patterns.

Introduction

Behavioral patterns are used in communication between entities to make communication easier and more flexible such as Iterator, Command, Observer, State, Strategy, Chain of Responsibility, Mediator, and Template Method.
Behavioral design patterns are a type of design pattern that focuses on the communication and interaction between objects in a system. These patterns provide a way to define the communication between objects in a way that makes the system more flexible, reusable, and maintainable. Among the most popular behavioral design patterns are:

We’ll dive into commonly used patterns which are Strategy and Template patterns 

Strategy Pattern

The Strategy pattern is a behavioral design pattern that defines a family of algorithms, objects them, and makes them interchangeable. This pattern enables the runtime selection of an algorithm based on the context or specific requirements.

The following are the key elements of the strategy pattern:

This is the class that requires the use of an algorithm. It keeps a reference to a Strategy object and communicates with it to carry out the algorithm.

Strategy: This is an interface or abstract class that defines a set of methods that are shared by all algorithms. These methods are used by the Context class to communicate with the chosen algorithm.

Concrete Strategies are classes that implement the Strategy interface and implement their algorithms.

Let’s implement this in Go. 

  • Let’s define a struct with sum and difference and WrapperStruct which holds the algorithm provided and the actual implementation of an algorithm


// sum and difference struct for algorithm implementation
type sum struct{}

type difference struct{}

// Wrapper struct with algorithm embedded in it
type WrapperStruct struct {
	algorithm IAlgorithm
}

// Implementation of algorithms
func (s sum) ExecuteAlgorithm(a, b int) int {
	return a + b
}
func (d difference) ExecuteAlgorithm(a, b int) int {
	return a - b
}

  • Interface with function which implements algorithm logic and implementation of an individual is provided above also the function for the embedding algo in wrapper struct.

// Interface with algorithm algorithm function
type IAlgorithm interface {
	ExecuteAlgorithm(a, b int) int
}

// method to embed algo with wrapper struct
func setAlgorithm(algo IAlgorithm) WrapperStruct {
	return WrapperStruct{algorithm: algo}
}

And finally, the main method to call the algorithm


func main() {
	s := sum{}
	fmt.Println(setAlgorithm(s).algorithm.ExecuteAlgorithm(10, 10))

	d := difference{}
	fmt.Println(setAlgorithm(d).algorithm.ExecuteAlgorithm(10, 10))
}

So, the output will be 20 and 0.

Template Pattern

The Template Method pattern is a behavioral design pattern in which the skeleton of an algorithm is defined in a method called the Template Method and allows subclasses to redefine specific steps of the algorithm without changing the overall structure.

The Template Method pattern's key components are as follows:


Abstract Class: This is the class that defines the template method and the algorithm's skeleton. It also defines the methods that subclasses will override to provide their implementations.

Concrete Subclasses: These are classes that provide specific implementations of the template method's steps. They also can override other methods defined in the abstract class.

The template method defines the overall structure of the algorithm and calls the methods that the subclasses must implement. This pattern allows the overall structure of the algorithm to be separated from the specifics of the implementation.

Let’s make our hands dirty in the code.

  • We have an interface which has a set of methods which each object needs to implement and also a template method which this method called one by one according to its flow
  • Now we will implement RegularUser and Premium User both should implement the above interface individually 

type RegularUser struct {
	name string
	age  int
}
func (r RegularUser) createUser() {
	fmt.Sprintf("Regular User Created ! name : %s, age : %d", r.name, r.age)
}

func (p RegularUser) getUserMessage() string {
	return fmt.Sprintf("Hi,%s your account is created successfully!", p.name)
}
func (p RegularUser) getAdminMessage() string {
	return fmt.Sprintf("New Regular User Registration! Name %s, Age:%d", p.name, p.age)
}

  • PremiumUser concrete implementation

type PremiumUser struct {
	name string
	age  int
}

func (p PremiumUser) createUser() {
	fmt.Sprintf("Premium User Created ! name : %s, age : %d", p.name, p.age)
}
func (p PremiumUser) getUserMessage() string {
	return fmt.Sprintf(""Hello,%s, your premium account has been successfully created!" %s", p.name)
}

func (p PremiumUser) getAdminMessage() string {
	return fmt.Sprintf("New Premium User Registration! Name %s \t Age:%d", p.name, p.age)
}

And the main function will look like this


func sendMessage(message string) {
	fmt.Println(message)
}
func main() {
	r := RegularUser{name: "John", age: 20}
	user := UserCreation{userActivities: r}
	user.createAndNotifyUser()

	p := RegularUser{name: "Doe", age: 21}
	user = UserCreation{userActivities: p}
	user.createAndNotifyUser()
}

Conclusion : 

In conclusion, behavioral design patterns are a powerful tool for managing and organizing the behavior of objects in an application. These patterns provide a common vocabulary for discussing and solving common problems related to object interaction and communication. By understanding and applying these patterns, developers can create more flexible, maintainable, and efficient code. Some of the most popular behavioral patterns include the Observer, Mediator, and template method, strategy each of which addresses specific challenges related to object communication and coordination. Overall, the use of behavioral design patterns can greatly improve the design of an application and make it more robust and easier to understand and maintain.

Hello, I am Akshay Navale, a highly driven and passionate software developer, avid learner, and tech enthusiast, always striving to do better. My passion for technology drives me to continuously learn and improve.

Want to receive update about our upcoming podcast?

Thanks for joining our newsletter.
Oops! Something went wrong.