Mastering Design Patterns: Strategy, Factory, Singleton, Proxy, Observer, Template & Adapter in Java
This article provides a comprehensive, code‑first guide to the most common design patterns—including Strategy, Simple Factory, Singleton, Proxy, Factory Method, Observer, Template Method and Adapter—explaining their concepts, real‑world use cases, and complete Java implementations with Spring Boot integration.
Introduction
Design patterns are reusable solutions to recurring software design problems. When a pattern fits the problem context, it can be applied across domains such as Domain‑Driven Design (DDD) or classic object‑oriented design.
Common Design Patterns
Strategy
Factory
Singleton
Proxy
Factory Method
Observer
Template Method
Adapter
1. Strategy Pattern
Scenario: a retail promotion applies different discount rates based on purchase amount. The Strategy interface defines String strategy() (identifier) and void algorithm() (business logic). Three concrete strategies (A, B, C) implement the interface, each printing its own processing message.
Strategy enumeration ( StrategySelector) maps a numeric code to a string identifier. StrategyRunner holds a List<Strategy> and builds a Map<String, Strategy> for fast lookup. The execute(String strategy) method retrieves the appropriate Strategy and runs its algorithm().
Spring Boot configuration registers all Strategy beans automatically. A controller exposes an endpoint /designPatterns/algorithm?strategy=... that delegates to strategyRunner.execute(), producing console output such as process with strategyA....
2. Simple Factory Pattern
Scenario: a payment system supports Alipay, WeChat Pay, and UnionPay. An IPayment interface defines Boolean pay(PaymentBody). Concrete implementations ( AliPay, WechatPay, UnionPay) print the payment channel and return TRUE.
The PaymentFactory uses EnumUtil to map a payment type to the fully‑qualified class name and creates the strategy via reflection. PayStrategyEnum stores the mapping.
A PaymentContext receives an IPayment instance and forwards the pay call. PaymentStrategyHandler validates the type, obtains the strategy from the factory, builds a context, and executes the payment. A REST controller provides a /designPatterns/pay POST endpoint.
3. Singleton Pattern
Implemented with a static inner holder class ( SingletonInstance) that contains a final INSTANCE. The public getInstance() method returns the holder’s instance, guaranteeing lazy, thread‑safe initialization.
4. Proxy Pattern
Real‑world analogy: a landlord delegates rental to a real‑estate agent. The Subject interface declares void rentHouse(). HouseOwner implements the actual rental logic. HouseProxy holds a HouseOwner reference and adds a proxy fee before delegating the call. A controller invokes the proxy via a REST endpoint.
5. Factory Method Pattern
Defines an abstract NetworkConfigFactoryService with
NetworkConfigCrudService getSpecificService(String productType). The concrete NetworkConfigFactoryServiceImpl injects four service implementations (A‑D) and selects one via a switch. Each service implements NetworkConfigCrudService and returns a NetworkConfigVO. A controller demonstrates fetching a specific service and returning the result.
6. Observer Pattern
Illustrated with a weather‑station example. Subject defines registration, removal, and notification methods. Observer defines update(float temp, float humidity, float pressure). WeatherData implements Subject, stores observers, and notifies them when measurements change. CurrentConditionDisplay implements both Observer and Display, updating its state and printing a message. A variant uses Java’s built‑in Observable and Observer interfaces.
7. Template Method Pattern
Abstract class HouseTemplate defines the final buildHouse() algorithm: build foundation, pillars, walls, windows, then print success. Subclasses must implement buildPillars() and buildWalls(). Concrete subclasses ( WoodenHouse, GlassHouse, ConcreteHouse) provide specific pillar and wall implementations. A client creates each house type and calls buildHouse(), producing ordered output.
8. Adapter Pattern
Class adapter example: an Adaptee (network cable) provides request(). Target interface NetToUsb declares handleRequest(). Adapter extends Adaptee and implements NetToUsb, delegating handleRequest() to super.request(). A Computer class expects a NetToUsb and calls net(adapter). The main method wires everything together.
Conclusion
Design patterns encapsulate proven object‑oriented solutions. Understanding their intent, structure, and Java implementation—especially when combined with Spring Boot’s dependency injection—helps developers write flexible, maintainable code.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
IT Architects Alliance
Discussion and exchange on system, internet, large‑scale distributed, high‑availability, and high‑performance architectures, as well as big data, machine learning, AI, and architecture adjustments with internet technologies. Includes real‑world large‑scale architecture case studies. Open to architects who have ideas and enjoy sharing.
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.
