Strategy Pattern
Part of the Object Oriented Programming section of Coddy's Java journey — lesson 69 of 87.
The Strategy Pattern is a behavioral design pattern that lets you define a family of algorithms, encapsulate each one in its own class, and make them interchangeable. Instead of hardcoding a specific behavior, you can swap algorithms at runtime without changing the code that uses them.
Imagine a payment system that supports multiple payment methods. Without the Strategy Pattern, you'd end up with messy conditional logic. With it, each payment method becomes its own strategy:
interface PaymentStrategy {
void pay(int amount);
}
class CreditCardPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " via Credit Card");
}
}
class PayPalPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " via PayPal");
}
}The context class holds a reference to a strategy and delegates the work to it. The key is that the context doesn't know which concrete strategy it's using—it only knows the interface:
class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy strategy) {
this.paymentStrategy = strategy;
}
public void checkout(int amount) {
paymentStrategy.pay(amount);
}
}Now you can change the payment behavior dynamically:
ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(new CreditCardPayment());
cart.checkout(100); // Paid 100 via Credit Card
cart.setPaymentStrategy(new PayPalPayment());
cart.checkout(50); // Paid 50 via PayPalThe Strategy Pattern shines when you have multiple ways to perform an action and want to switch between them easily. Adding a new payment method simply means creating a new class that implements PaymentStrategy—no changes to existing code required.
Challenge
EasyLet's build a text formatting system using the Strategy Pattern! You'll create a system where different formatting strategies can be swapped at runtime to transform text in various ways—perfect for an application that needs to support multiple output formats.
You'll organize your code across four files:
TextFormatter.java: Define theTextFormatterinterface that all formatting strategies will implement. It should declare a single methodString format(String text)that takes a string and returns the formatted version.Formatters.java: Create three concrete strategies that implement yourTextFormatterinterface:UpperCaseFormatter- transforms the text to all uppercase letters.LowerCaseFormatter- transforms the text to all lowercase letters.TitleCaseFormatter- capitalizes the first letter of each word while making the rest lowercase. Words are separated by spaces.TextEditor.java: Create the context class that uses a formatting strategy. YourTextEditorshould have:A private field to hold the current
TextFormatterstrategy.A
setFormatter(TextFormatter formatter)method that changes the active formatting strategy.A
publishText(String text)method that applies the current formatter to the text and printsPublished: [formatted text]. If no formatter has been set, it should printPublished: [original text]unchanged.Main.java: Bring your strategy system together! You'll receive two inputs: the text to format (String) and the formatting style (String:"upper","lower", or"title").Create a
TextEditorand first callpublishTextwith your input text before setting any formatter (demonstrating the default behavior).Then, based on the style input, set the appropriate formatter strategy and call
publishTextagain with the same text to show the formatted result.
You will receive two inputs in order: the text to format (String) and the formatting style (String).
For example, with inputs hello world and title, your output would be:
Published: hello world
Published: Hello WorldNotice how the TextEditor doesn't know anything about the specific formatting logic—it simply delegates to whatever strategy is currently set. This makes it trivial to add new formatting styles without touching the editor code!
Cheat sheet
The Strategy Pattern is a behavioral design pattern that defines a family of algorithms, encapsulates each one in its own class, and makes them interchangeable. It allows swapping algorithms at runtime without changing the code that uses them.
Key Components
Strategy Interface: Defines the common interface for all concrete strategies.
interface PaymentStrategy {
void pay(int amount);
}Concrete Strategies: Implement the strategy interface with specific algorithms.
class CreditCardPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " via Credit Card");
}
}
class PayPalPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " via PayPal");
}
}Context Class: Holds a reference to a strategy and delegates work to it. The context only knows the interface, not the concrete implementation.
class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy strategy) {
this.paymentStrategy = strategy;
}
public void checkout(int amount) {
paymentStrategy.pay(amount);
}
}Usage
Strategies can be changed dynamically at runtime:
ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(new CreditCardPayment());
cart.checkout(100); // Paid 100 via Credit Card
cart.setPaymentStrategy(new PayPalPayment());
cart.checkout(50); // Paid 50 via PayPalBenefits
The Strategy Pattern is ideal when you have multiple ways to perform an action and want to switch between them easily. Adding a new strategy simply means creating a new class that implements the strategy interface—no changes to existing code required.
Try it yourself
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String text = scanner.nextLine();
String style = scanner.nextLine();
// TODO: Create a TextEditor instance
// TODO: Call publishText with the input text (before setting any formatter)
// TODO: Based on the style input ("upper", "lower", or "title"),
// set the appropriate formatter and call publishText again
}
}This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesIntroduction to OOPClasses vs ObjectsThe this KeywordMethodsFields (Attributes)Constructor MethodConstructor OverloadingRecap - Simple Calculator4Inheritance
Basic Inheritance (extends)The super KeywordMethod Overriding (@Override)Constructor ChainingThe Object ClassSingle & Multilevel InheritWhy No Multi Class InheritRecap - Employee Hierarchy7Special Methods & Object Class
toString() Methodequals() and hashCode()clone() MethodcompareTo() and ComparableComparator InterfaceRecap - Custom Sorting2Access Modifiers & Encapsulate
Access Levels OverviewGetter and Setter MethodsInformation HidingThe final KeywordRecap - Bank Account Manager5Polymorphism
Method Overloading BasicsMethod Overriding (Run-Time)Upcasting and DowncastingThe instanceof OperatorAbstract Classes and MethodsRecap - Shape Calculator8Advanced OOP Concepts
Composition vs InheritanceAggregation vs CompositionInner Nested & Anonymous ClassEnums and Enum MethodsRecords (Java 16+)Sealed Classes (Java 17+)11Design Patterns Part 1
Intro to Design PatternsSingleton PatternFactory PatternBuilder PatternObserver PatternStrategy Pattern3Class Props & Static Member
Instance vs Static VariablesStatic MethodsStatic BlocksConstants (static final)Recap - Counter & Utility6Interfaces & Abstract Classes
Introduction to InterfacesImplementing InterfacesMulti Interface ImplemenDefault & Static in InterfaceAbstract Classes vs InterfacesFunctional InterfacesRecap - Payment System