Strategy Pattern Implementation for JSON Processing
The Strategy pattern provides a way to encapsulate a family of algorithms and make them interchangeable. In this example, we refactored a rigid JSON converter into a more flexible strategy-based solution for processing different types of JSON data.
Before: Hard-Coded JSON Conversion
Previously, our UserPreferencesJsonConverter class contained hard-coded logic with explicit checks for specific JSON keys:
This approach violates the Open Closed Principle (OCP) because the class must be modified every time a new JSON format needs to be supported. Adding a new format requires changing the existing code, increasing the risk of regression bugs.
After: Strategy Pattern Implementation
1. Define the Strategy Interface
2. Implement Concrete Strategies
3. Context Class Using the Strategies
4. Register Strategies with Dependency Injection
This registration pattern leverages a key behavior of most DI containers: when multiple implementations of the same interface are registered, injecting IEnumerable<IJsonProcessor> will provide all registered implementations in the order they were defined. This is crucial for our strategy pattern implementation as it allows the UserPreferencesService to automatically receive all JSON processors without modification. If we had injected just IJsonProcessor (without the IEnumerable), only the last registered implementation would be available, defeating the purpose of our flexible processor system. When adding a new JSON processor, simply register it in the DI container and it becomes immediately available to all consumers of IEnumerable<IJsonProcessor> without any code changes in those consumers - a perfect demonstration of the Open/Closed Principle in action.
This strategy pattern implementation adheres to the Open/Closed Principle by allowing the system to be extended with new JSON processors without modifying existing code. Adding support for a new JSON format is simply a matter of:
Creating a new class that implements
IJsonProcessorRegistering it with the dependency injection container
The core processing logic in UserPreferencesService remains unchanged, reducing the risk of introducing bugs while enhancing the system's capability.
See Also:
Explicit case analysis (switch/if-else statement) (Strategy pattern is an alternative)
Prefer Dictionary to Switch Statement (Another alternative)
Find What Is Varying and Encapsulate It (Shalloway 123) (Strategy encapsulates varying algorithms)