Deep Dive into Flutter Design Patterns [part 2] [Behavioural design Pattern]
In our previous discussion, we delved into the basics of Design Patterns, beginning with the Factory Design Pattern - a cornerstone of the Creational Design Pattern Family. Today, we will be shifting out focus to the Behavioural Design Pattern and explore its applications.
Understanding Behavioural Design pattern
According to Gang of Four (GoF) design pattern, Behavioural design patterns are design patterns which provide solutions for better interaction between objects.
Strategy Design Pattern
Strategy Design Pattern is a behavioural design pattern which defines a family of algorithm and englobes them into a class and makes them interchangeable. The algorithm will as well dynamically change depending on the client.
Problem Statement
Imagine you have a button that, for now, only displays in red. In the future, you plan to introduce a blue button with a distinct behaviour compared to the red one. Additionally, there's potential for further button variations down the line.
class BeforeStrategy extends StatefulWidget {
const BeforeStrategy({super.key});
@override
State<BeforeStrategy> createState() => _BeforeStrategyState();
}
class _BeforeStrategyState extends State<BeforeStrategy> {
bool isRedButton = false;
@override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
onPressed: () {
if (isRedButton) {
setState(() {
print("I am a red button");
});
}
},
child: Text("Red Strategy"),
),
);
}
}
Modifying the above code to implement a blue button would look as such:
class _BeforeStrategyState extends State<BeforeStrategy> {
bool isRedButton = false;
@override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
onPressed: () {
if (isRedButton) {
setState(() {
print("I am a red button");
});
} else {
setState(() {
print("I am a blue button");
});
}
},
child: Text("Red Strategy"),
),
);
}
}
Solution
The strategy pattern recommends encapsulating algorithms into distinct classes, allowing the behaviour to be selected and swapped at runtime without altering the classes that use them.
The primary benefit to this approach includes encapsulation, separation of concerns, and the ability to change behaviour dynamically.
Moreover it adheres to the Open/Closed Principle; that software should be open for extension but closed for modification, by allowing new strategies to be added without modifying the existing code.
Refining the code provided above as follows:
abstract class ButtonStrategy {
void execute();
}
import 'package:design_patterns/strategies/abstractButtonStrategy.dart';
class BlueButtonStrategy implements ButtonStrategy {
@override
void execute() {
print("i am a blue button");
}
}
import 'package:design_patterns/strategies/abstractButtonStrategy.dart';
class RedButtonStrategy implements ButtonStrategy {
@override
void execute() {
print("i am a red button");
}
}
class ViewButtonStrategy extends StatefulWidget {
const ViewButtonStrategy({super.key});
@override
State<ViewButtonStrategy> createState() => _ViewButtonStrategyState();
}
class _ViewButtonStrategyState extends State<ViewButtonStrategy> {
bool isRedButton = false;
ButtonStrategy? buttonStrategy;
@override
void initState() {
super.initState();
updateStategy();
}
updateStategy() {
if (isRedButton) {
buttonStrategy = RedButtonStrategy();
} else {
buttonStrategy = BlueButtonStrategy();
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () {
buttonStrategy?.execute();
setState(() {
isRedButton = !isRedButton;
updateStategy();
});
},
child: Text("Test Stategy"),
),
),
);
}
}
Explanation of the above code:
The context, which in our case is the ViewButtonStrategy will be in charge of communicating with the strategies which are RedButtonStrategy() and BlueButtonStrategy().
The strategy interface serves as a common blueprint for all the concrete strategies.
Concrete strategies are tasked with implementing the specific algorithms.
At run time, the client decides which algorithm to use; in this use case, strategy to use will depend on "isRedButton". Therefore once the button is pressed, it leads to a change in the strategy.
Wrapping Up
And that’s it guys! I hope you have a better understanding of Strategy Pattern!
References:
About Me
I am Zaahra, a Google Women Techmakers Ambassador who enjoy mentoring people and writing about technical contents that might help people in their developer journey. I also enjoy building stuffs to solve real life problems.
To reach me:
LinkedIn: https://www.linkedin.com/in/faatimah-iz-zaahra-m-0670881a1/
X (previously Twitter): _fz3hra
GitHub: https://github.com/fz3hra
Cheers,
Umme Faatimah-Iz-Zaahra Mujore | Google Women TechMakers Ambassador | Software Engineer