Strategy Design Pattern in Java: Definition, Structure, Example, and Refactoring
This article explains the behavioral Strategy design pattern, describes its definition and structure, demonstrates a real‑world e‑commerce discount scenario with both a tangled if‑else implementation and a clean refactoring using Java interfaces, concrete strategy classes, a context, and a client, and finally discusses its advantages and drawbacks.
Design patterns are divided into creational, structural, and behavioral categories; the Strategy pattern belongs to the behavioral group and is widely used in JDK source code and the Spring framework to improve code extensibility.
Definition : Strategy defines a family of algorithms, encapsulates each one, and makes them interchangeable; the algorithm can vary independently of the client that uses it.
Structure :
Strategy : abstract strategy class or interface that declares common methods.
Concrete Strategy : classes that implement the abstract methods with specific algorithms.
Context : holds a reference to a Strategy object and delegates the algorithm execution to it.
Case Study : An e‑commerce promotion rule with four member types (non‑member, ordinary, silver, gold) and different discount calculations.
Non‑refactored code (many nested if‑else statements) is shown below:
public long calculate(String userType, long amount) {
if ("ordinary".equals(userType)) {
if (amount > 200) {
return amount / 100 * 90;
}
return amount;
}
if ("silver".equals(userType)) {
if (amount > 300) {
return amount / 100 * 80 - 20;
}
return amount / 100 * 80;
}
if ("golden".equals(userType)) {
if (amount > 300) {
return amount / 100 * 60;
}
return amount / 100 * 70;
}
return amount;
}Refactored version using Strategy:
Strategy Interface
package com.sample.patterns.strategy;
public interface PromotionStrategy {
// calculate amount after promotion
long calculate(long amount);
}Concrete Strategies
package com.sample.patterns.strategy;
// Non‑member strategy
public class NonMemberStrategy implements PromotionStrategy {
@Override
public long calculate(long amount) {
return amount;
}
} package com.sample.patterns.strategy;
// Ordinary member strategy (9% discount over 200)
public class OrdinaryMemberStrategy implements PromotionStrategy {
@Override
public long calculate(long amount) {
if (amount > 200) {
return amount / 100 * 90;
}
return amount;
}
} package com.sample.patterns.strategy;
// Silver member strategy (20% discount, extra 20 off over 300)
public class SilverMemberStrategy implements PromotionStrategy {
@Override
public long calculate(long amount) {
if (amount > 300) {
return amount / 100 * 80 - 20;
}
return amount / 100 * 80;
}
} package com.sample.patterns.strategy;
// Gold member strategy (30% discount, 40% discount over 300)
public class GoldenMemberStrategy implements PromotionStrategy {
@Override
public long calculate(long amount) {
if (amount > 300) {
return amount / 100 * 60;
}
return amount / 100 * 70;
}
}Context
package com.sample.patterns.strategy;
public class PromotionContext {
// promotion strategy
private PromotionStrategy promotionStrategy;
public PromotionContext(PromotionStrategy promotionStrategy) {
this.promotionStrategy = promotionStrategy;
}
// calculate amount after promotion
public long calculate(long amount) {
return promotionStrategy.calculate(amount);
}
}Client Test
package com.sample.patterns.strategy;
public class PromotionClient {
public static void main(String[] args) {
// four promotion contexts
PromotionContext nonMemberContext = new PromotionContext(new NonMemberStrategy());
PromotionContext ordinaryMemberContext = new PromotionContext(new OrdinaryMemberStrategy());
PromotionContext silverMemberContext = new PromotionContext(new SilverMemberStrategy());
PromotionContext goldenMemberContext = new PromotionContext(new GoldenMemberStrategy());
// example amount 500
System.out.println(nonMemberContext.calculate(500)); // 500
System.out.println(ordinaryMemberContext.calculate(500)); // 450
System.out.println(silverMemberContext.calculate(500)); // 380
System.out.println(goldenMemberContext.calculate(500)); // 300
}
}The output matches the required discount rules, and any future rule change only requires modifying or adding a concrete strategy class, leaving other code untouched.
Summary : The Strategy pattern cleanly separates algorithm implementations from their usage, adhering to the Open‑Closed Principle, improving maintainability and extensibility. It is suitable for any scenario where multiple interchangeable algorithms are needed (e.g., different file upload handlers, cooking methods, etc.).
Advantages :
Open for extension, closed for modification.
Separates algorithm details from client code.
Eliminates complex conditional statements.
Disadvantages :
Can lead to many small strategy classes with limited reuse.
Client must be aware of all concrete strategies to choose the right one.
Introducing a Context adds an extra layer, increasing design complexity and slight performance overhead.
For further discussion, feel free to add the author’s WeChat (remark "Internet Full‑Stack Architecture") or leave comments.
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.