<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ design patterns - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ design patterns - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Fri, 15 May 2026 22:29:59 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/design-patterns/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Use the Command Pattern in Python ]]>
                </title>
                <description>
                    <![CDATA[ Have you ever used an undo button in an app or scheduled tasks to run later? Both of these rely on the same idea: turning actions into objects. That's the command pattern. Instead of calling a method  ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-the-command-pattern-in-python/</link>
                <guid isPermaLink="false">69c1abb330a9b81e3aa82e36</guid>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ design patterns ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Bala Priya C ]]>
                </dc:creator>
                <pubDate>Mon, 23 Mar 2026 21:08:03 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/85170982-e7e8-453a-9fd4-a7f2f4f7edb3.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Have you ever used an undo button in an app or scheduled tasks to run later? Both of these rely on the same idea: <strong>turning actions into objects</strong>.</p>
<p>That's the command pattern. Instead of calling a method directly, you package the call – the action, its target, and any arguments – into an object. That object can be stored, passed around, executed later, or undone.</p>
<p>In this tutorial, you'll learn what the command pattern is and how to implement it in Python with a practical text editor example that supports undo.</p>
<p>You can find the code for this tutorial <a href="https://github.com/balapriyac/python-basics/tree/main/design-patterns/command">on GitHub</a>.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before we start, make sure you have:</p>
<ul>
<li><p>Python 3.10 or higher installed</p>
</li>
<li><p>Basic understanding of Python classes and methods</p>
</li>
<li><p>Familiarity with object-oriented programming (OOP) concepts</p>
</li>
</ul>
<p>Let's get started!</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-what-is-the-command-pattern">What Is the Command Pattern?</a></p>
</li>
<li><p><a href="#heading-setting-up-the-receiver">Setting Up the Receiver</a></p>
</li>
<li><p><a href="#heading-defining-commands">Defining Commands</a></p>
</li>
<li><p><a href="#heading-the-invoker-running-and-undoing-commands">The Invoker: Running and Undoing Commands</a></p>
</li>
<li><p><a href="#heading-putting-it-all-together">Putting It All Together</a></p>
</li>
<li><p><a href="#heading-when-to-use-the-command-pattern">When to Use the Command Pattern</a></p>
</li>
</ul>
<h2 id="heading-what-is-the-command-pattern">What Is the Command Pattern?</h2>
<p>The <strong>command pattern</strong> is a behavioral design pattern that encapsulates a request as an object. This lets you:</p>
<ul>
<li><p><strong>Parameterize</strong> callers with different operations</p>
</li>
<li><p><strong>Queue or schedule</strong> operations for later execution</p>
</li>
<li><p><strong>Support undo/redo</strong> by keeping a history of executed commands</p>
</li>
</ul>
<p>The pattern has four key participants:</p>
<ul>
<li><p><strong>Command</strong>: an interface with an <code>execute()</code> method (and optionally <code>undo()</code>)</p>
</li>
<li><p><strong>Concrete Command</strong>: implements <code>execute()</code> and <code>undo()</code> for a specific action</p>
</li>
<li><p><strong>Receiver</strong>: the object that actually does the work (for example, a document)</p>
</li>
<li><p><strong>Invoker</strong>: triggers commands and manages history</p>
</li>
</ul>
<p>Think of a restaurant. The customer (client) tells the waiter (invoker) what they want. The waiter writes it on a ticket (command) and hands it to the kitchen (receiver). The waiter doesn't cook – they only manage tickets. If you change your mind, the waiter can cancel the ticket before it reaches the kitchen.</p>
<h2 id="heading-setting-up-the-receiver">Setting Up the Receiver</h2>
<p>We'll build a simple document editor. The <strong>receiver</strong> here is the <code>Document</code> class. It knows how to insert and delete text, but it has no idea who's calling it or why.</p>
<pre><code class="language-python">class Document:
    def __init__(self):
        self.content = ""

    def insert(self, text: str, position: int) -&gt; None:
        self.content = (
            self.content[:position] + text + self.content[position:]
        )

    def delete(self, position: int, length: int) -&gt; None:
        self.content = (
            self.content[:position] + self.content[position + length:]
        )

    def show(self) -&gt; None:
        print(f'Document: "{self.content}"')
</code></pre>
<p><code>insert</code> places text at a given position. <code>delete</code> removes <code>length</code> characters from a given position. Both are plain methods with no history or awareness of commands. And that's intentional.</p>
<h2 id="heading-defining-commands">Defining Commands</h2>
<p>Now let's define a base <code>Command</code> interface using an abstract class:</p>
<pre><code class="language-python">from abc import ABC, abstractmethod

class Command(ABC):
    @abstractmethod
    def execute(self) -&gt; None:
        pass

    @abstractmethod
    def undo(self) -&gt; None:
        pass
</code></pre>
<p>Any concrete command must implement both <code>execute</code> and <code>undo</code>. This is what makes a full history possible.</p>
<h3 id="heading-insertcommand"><code>InsertCommand</code></h3>
<p><code>InsertCommand</code> stores the text and position at creation time:</p>
<pre><code class="language-python">class InsertCommand(Command):
    def __init__(self, document: Document, text: str, position: int):
        self.document = document
        self.text = text
        self.position = position

    def execute(self) -&gt; None:
        self.document.insert(self.text, self.position)

    def undo(self) -&gt; None:
        self.document.delete(self.position, len(self.text))
</code></pre>
<p>When <code>execute()</code> is called, it inserts the text. When <code>undo()</code> is called, it deletes exactly what was inserted. Notice that <code>undo</code> is the inverse of <code>execute</code> – this is the key design requirement.</p>
<h3 id="heading-deletecommand"><code>DeleteCommand</code></h3>
<p>Now let's code the <code>DeleteCommand</code>:</p>
<pre><code class="language-python">class DeleteCommand(Command):
    def __init__(self, document: Document, position: int, length: int):
        self.document = document
        self.position = position
        self.length = length
        self._deleted_text = ""  # stored on execute, used on undo

    def execute(self) -&gt; None:
        self._deleted_text = self.document.content[
            self.position : self.position + self.length
        ]
        self.document.delete(self.position, self.length)

    def undo(self) -&gt; None:
        self.document.insert(self._deleted_text, self.position)
</code></pre>
<p><code>DeleteCommand</code> has one important detail: it captures the deleted text <em>during</em> <code>execute()</code>, not at creation time. This is because we don't know what text is at that position until the command actually runs. Without this, <code>undo()</code> wouldn't know what to restore.</p>
<h2 id="heading-the-invoker-running-and-undoing-commands">The Invoker: Running and Undoing Commands</h2>
<p>The <strong>invoker</strong> is the object that executes commands and keeps a history stack. It has no idea what a document is or how text editing works. It just manages command objects.</p>
<pre><code class="language-python">class EditorInvoker:
    def __init__(self):
        self._history: list[Command] = []

    def run(self, command: Command) -&gt; None:
        command.execute()
        self._history.append(command)

    def undo(self) -&gt; None:
        if not self._history:
            print("Nothing to undo.")
            return
        command = self._history.pop()
        command.undo()
        print("Undo successful.")
</code></pre>
<p><code>run()</code> executes the command and pushes it onto the history stack. <code>undo()</code> pops the last command and calls its <code>undo()</code> method. The stack naturally gives you the right order: last in, first undone.</p>
<h2 id="heading-putting-it-all-together">Putting It All Together</h2>
<p>Let's put it all together and walk through a real editing session:</p>
<pre><code class="language-python">doc = Document()
editor = EditorInvoker()

# Type a title
editor.run(InsertCommand(doc, "Quarterly Report", 0))
doc.show()

# Add a subtitle
editor.run(InsertCommand(doc, " - Finance", 16))
doc.show()

# Oops, wrong subtitle — undo it
editor.undo()
doc.show()

# Delete "Quarterly" and replace with "Annual"
editor.run(DeleteCommand(doc, 0, 9))
doc.show()

editor.run(InsertCommand(doc, "Annual", 0))
doc.show()

# Undo the insert
editor.undo()
doc.show()

# Undo the delete (restores "Quarterly")
editor.undo()
doc.show()
</code></pre>
<p>This outputs:</p>
<pre><code class="language-plaintext">Document: "Quarterly Report"
Document: "Quarterly Report - Finance"
Undo successful.
Document: "Quarterly Report"
Document: " Report"
Document: "Annual Report"
Undo successful.
Document: " Report"
Undo successful.
Document: "Quarterly Report"
</code></pre>
<p>Here's the step-by-step breakdown of how (and why) this works:</p>
<ul>
<li><p>Each <code>InsertCommand</code> and <code>DeleteCommand</code> carries its own instructions for both doing and undoing.</p>
</li>
<li><p><code>EditorInvoker</code> never looks inside a command. It only calls <code>execute()</code> and <code>undo()</code>.</p>
</li>
<li><p>The document (<code>Document</code>) never thinks about history. It mutates its content when told to.</p>
</li>
</ul>
<p>Each participant has a single, clear responsibility.</p>
<h2 id="heading-extending-with-macros">Extending with Macros</h2>
<p>One of the lesser-known benefits of the command pattern is that commands are just objects. So you can group them. Here's a <code>MacroCommand</code> that batches several commands and undoes them as a unit:</p>
<pre><code class="language-python">class MacroCommand(Command):
    def __init__(self, commands: list[Command]):
        self.commands = commands

    def execute(self) -&gt; None:
        for cmd in self.commands:
            cmd.execute()

    def undo(self) -&gt; None:
        for cmd in reversed(self.commands):
            cmd.undo()

# Apply a heading format in one shot: clear content, insert formatted title
macro = MacroCommand([
    DeleteCommand(doc, 0, len(doc.content)),
    InsertCommand(doc, "== Annual Report ==", 0),
])

editor.run(macro)
doc.show()

editor.undo()
doc.show()
</code></pre>
<p>This gives the following output:</p>
<pre><code class="language-plaintext">Document: "== Annual Report =="
Undo successful.
Document: "Quarterly Report"
</code></pre>
<p>The macro undoes its commands in reverse order. This is correct since the last thing done should be the first thing undone.</p>
<h2 id="heading-when-to-use-the-command-pattern">When to Use the Command Pattern</h2>
<p>The command pattern is a good fit when:</p>
<ul>
<li><p><strong>You need undo/redo</strong>: the pattern is practically made for this. Store executed commands in a stack and reverse them.</p>
</li>
<li><p><strong>You need to queue or schedule operations</strong>: commands are objects, so you can put them in a queue, serialize them, or delay execution.</p>
</li>
<li><p><strong>You want to decouple the caller from the action</strong>: the invoker doesn't need to know what the command does. It just runs it.</p>
</li>
<li><p><strong>You need to support macros or batched operations</strong>: group commands into a composite and run them together, as shown above.</p>
</li>
</ul>
<p>Avoid it when:</p>
<ul>
<li><p>The operations are simple and will never need undo or queuing. The pattern adds classes and indirection that may not be worth it for a simple CRUD action.</p>
</li>
<li><p>Commands would need to share so much state that the "encapsulate the request" idea breaks down.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>I hope you found this tutorial useful. To summarize, the command pattern turns actions into objects. And that single idea unlocks a lot: undo/redo, queuing, macros, and clean separation between who triggers an action and what the action does.</p>
<p>We built a document editor from scratch using <code>InsertCommand</code>, <code>DeleteCommand</code>, an <code>EditorInvoker</code> with a history stack, and a <code>MacroCommand</code> for batched edits. Each class knew exactly one thing and did it well.</p>
<p>As a next step, try extending the editor with a <code>RedoCommand</code>. You'll need a second stack alongside the history to bring back undone commands.</p>
<p>Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Implement the Strategy Pattern in Python ]]>
                </title>
                <description>
                    <![CDATA[ Have you ever opened a food delivery app and chosen between "fastest route", "cheapest option", or "fewest stops"? Or picked a payment method at checkout like credit card, PayPal, or wallet balance? B ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-implement-the-strategy-pattern-in-python/</link>
                <guid isPermaLink="false">69b1d33d6c896b0519c3abdc</guid>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ design patterns ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Bala Priya C ]]>
                </dc:creator>
                <pubDate>Wed, 11 Mar 2026 20:40:29 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/8298ed99-c958-4b98-821e-ae43496b85af.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Have you ever opened a food delivery app and chosen between "fastest route", "cheapest option", or "fewest stops"? Or picked a payment method at checkout like credit card, PayPal, or wallet balance? Behind both of these, there's a good chance the <strong>strategy pattern</strong> is at work.</p>
<p>The strategy pattern lets you define a family of algorithms, put each one in its own class, and make them interchangeable at runtime. Instead of writing a giant <code>if/elif</code> chain every time behavior needs to change, you swap in the right strategy for the job.</p>
<p>In this tutorial, you'll learn what the strategy pattern is, why it's useful, and how to implement it in Python with practical examples.</p>
<p>You can get the code <a href="https://github.com/balapriyac/python-basics/tree/main/design-patterns/strategy">on GitHub</a>.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before we start, make sure you have:</p>
<ul>
<li><p>Python 3.10 or higher installed</p>
</li>
<li><p>Basic understanding of Python classes and methods</p>
</li>
<li><p>Familiarity with object-oriented programming (OOP) concepts</p>
</li>
</ul>
<p>Let's get started!</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-what-is-the-strategy-pattern">What Is the Strategy Pattern?</a></p>
</li>
<li><p><a href="#heading-a-simple-strategy-pattern-example">A Simple Strategy Pattern Example</a></p>
</li>
<li><p><a href="#heading-swapping-strategies-at-runtime">Swapping Strategies at Runtime</a></p>
</li>
<li><p><a href="#heading-using-abstract-base-classes">Using Abstract Base Classes</a></p>
</li>
<li><p><a href="#heading-when-to-use-the-strategy-pattern">When to Use the Strategy Pattern</a></p>
</li>
</ul>
<h2 id="heading-what-is-the-strategy-pattern">What Is the Strategy Pattern?</h2>
<p>The <strong>strategy pattern</strong> defines a way to encapsulate a group of related algorithms so they can be used interchangeably. The object that uses the algorithm, called the <strong>context</strong>, doesn't need to know how it works. It just delegates the work to whichever strategy is currently set.</p>
<p>Think of it like a GPS app. The destination is the same, but you can switch between "avoid highways", "shortest distance", or "least traffic" without changing the destination or the app itself. Each routing option is a separate strategy.</p>
<p>The pattern is useful when:</p>
<ul>
<li><p>You have multiple variations of an algorithm or behavior</p>
</li>
<li><p>You want to eliminate long <code>if/elif</code> conditionals based on type</p>
</li>
<li><p>You want to swap behavior at runtime without changing the context class</p>
</li>
<li><p>Different parts of your app need different variations of the same operation</p>
</li>
</ul>
<p>Now let's look at examples to understand this better.</p>
<h2 id="heading-a-simple-strategy-pattern-example">A Simple Strategy Pattern Example</h2>
<p>Let's build a simple e-commerce order system where different discount strategies can be applied at checkout.</p>
<p>First, let's create the three discount strategies:</p>
<pre><code class="language-python">class RegularDiscount:
    def apply(self, price):
        return price * 0.95  # 5% off

class SeasonalDiscount:
    def apply(self, price):
        return price * 0.80  # 20% off

class NoDiscount:
    def apply(self, price):
        return price  # no change
</code></pre>
<p>Each class has a single <code>apply</code> method that takes a price and returns the discounted price. They <strong>share the same interface but implement different logic</strong>: that's the key concept in the strategy pattern.</p>
<p>Now let's create the <code>Order</code> class that uses one of these strategies:</p>
<pre><code class="language-python">class Order:
    def __init__(self, product, price, discount_strategy):
        self.product = product
        self.price = price
        self.discount_strategy = discount_strategy

    def final_price(self):
        return self.discount_strategy.apply(self.price)

    def summary(self):
        print(f"Product : {self.product}")
        print(f"Original: ${self.price:.2f}")
        print(f"Final   : ${self.final_price():.2f}")
        print("-" * 30)
</code></pre>
<p>The <code>Order</code> class is our <strong>context</strong>. It doesn't contain any discount logic itself – it delegates that entirely to <code>discount_strategy.apply()</code>. Whichever strategy object you pass in, that's the one that runs.</p>
<p>Now let's place some orders:</p>
<pre><code class="language-python">order1 = Order("Mechanical Keyboard", 120.00, NoDiscount())
order2 = Order("Laptop Stand", 45.00, RegularDiscount())
order3 = Order("USB-C Hub", 35.00, SeasonalDiscount())

order1.summary()
order2.summary()
order3.summary()
</code></pre>
<p>Running the above code should give you the following output:</p>
<pre><code class="language-plaintext">Product : Mechanical Keyboard
Original: $120.00
Final   : $120.00
------------------------------
Product : Laptop Stand
Original: $45.00
Final   : $42.75
------------------------------
Product : USB-C Hub
Original: $35.00
Final   : $28.00
------------------------------
</code></pre>
<p>Notice how <code>Order</code> never checks <code>if discount_type == "seasonal"</code>. It just calls <code>apply()</code> and trusts the strategy to handle it. Adding a new discount type in the future means creating one new class and nothing else changes.</p>
<h2 id="heading-swapping-strategies-at-runtime">Swapping Strategies at Runtime</h2>
<p>One of the biggest advantages of the strategy pattern is that you can change the strategy while the program is running. Let's say a user upgrades to a premium membership mid-session:</p>
<pre><code class="language-python">class ShoppingCart:
    def __init__(self):
        self.items = []
        self.discount_strategy = NoDiscount()  # default

    def add_item(self, name, price):
        self.items.append({"name": name, "price": price})

    def set_discount(self, strategy):
        self.discount_strategy = strategy
        print(f"Discount updated to: {strategy.__class__.__name__}")

    def checkout(self):
        print("\n--- Checkout Summary ---")
        total = 0
        for item in self.items:
            discounted = self.discount_strategy.apply(item["price"])
            print(f"{item['name']}: ${discounted:.2f}")
            total += discounted
        print(f"Total: ${total:.2f}\n")
</code></pre>
<p>The <code>set_discount</code> method lets us replace the strategy at any point. Let's see it in action:</p>
<pre><code class="language-python">cart = ShoppingCart()
cart.add_item("Notebook", 15.00)
cart.add_item("Desk Lamp", 40.00)
cart.add_item("Monitor Riser", 25.00)

# Checkout as a regular customer
cart.checkout()

# User upgrades to seasonal sale membership
cart.set_discount(SeasonalDiscount())
cart.checkout()
</code></pre>
<p>This outputs:</p>
<pre><code class="language-plaintext">--- Checkout Summary ---
Notebook: $15.00
Desk Lamp: $40.00
Monitor Riser: $25.00
Total: $80.00

Discount updated to: SeasonalDiscount

--- Checkout Summary ---
Notebook: $12.00
Desk Lamp: $32.00
Monitor Riser: $20.00
Total: $64.00
</code></pre>
<p>The cart itself didn't change – only the strategy did. This is the advantage of keeping <em>behavior</em> separate from the <em>context</em> that uses it.</p>
<h2 id="heading-using-abstract-base-classes">Using Abstract Base Classes</h2>
<p>So far, nothing enforces that every strategy has an <code>apply</code> method. If someone creates a strategy and forgets it, they'll get a cryptic <code>AttributeError</code> at runtime. We can prevent that using <a href="https://docs.python.org/3/library/abc.html">Python's Abstract Base Classes</a>.</p>
<pre><code class="language-python">from abc import ABC, abstractmethod

class DiscountStrategy(ABC):
    @abstractmethod
    def apply(self, price: float) -&gt; float:
        pass
</code></pre>
<p>Now let's rewrite our strategies to inherit from it:</p>
<pre><code class="language-python">class RegularDiscount(DiscountStrategy):
    def apply(self, price):
        return price * 0.95

class SeasonalDiscount(DiscountStrategy):
    def apply(self, price):
        return price * 0.80

class NoDiscount(DiscountStrategy):
    def apply(self, price):
        return price
</code></pre>
<p>Now if someone creates a broken strategy without <code>apply</code>, Python will raise a <code>TypeError</code> immediately when they try to instantiate it — before any code runs. That's a much cleaner failure.</p>
<pre><code class="language-python">class BrokenStrategy(DiscountStrategy):
    pass  # forgot to implement apply()

s = BrokenStrategy()  # raises TypeError right here
</code></pre>
<p>Using ABCs is especially helpful on larger teams or in shared codebases, where you want to make the contract explicit: every strategy <em>must</em> implement <code>apply</code>. Else, you run into an error as shown.</p>
<pre><code class="language-plaintext">      2     pass  # forgot to implement apply()
      3 
----&gt; 4 s = BrokenStrategy()  # raises TypeError right here

TypeError: Can't instantiate abstract class BrokenStrategy without an implementation for abstract method 'apply'
</code></pre>
<h2 id="heading-when-to-use-the-strategy-pattern">When to Use the Strategy Pattern</h2>
<p>The Strategy pattern is a good fit when:</p>
<ul>
<li><p>You have branching logic based on type — long <code>if/elif</code> blocks that check a "mode" or "type" variable are a signal that Strategy might help.</p>
</li>
<li><p>Behavior needs to change at runtime — when users or config values should be able to switch algorithms without restarting.</p>
</li>
<li><p>You're building extensible systems — new behavior can be added as a new class without touching existing code.</p>
</li>
<li><p>You want to test algorithms independently — each strategy is its own class, making unit tests straightforward.</p>
</li>
</ul>
<p>Avoid it when:</p>
<ul>
<li><p>You only have two variations that will never grow — a simple <code>if/else</code> is perfectly fine there.</p>
</li>
<li><p>The strategies share so much state that separating them into classes adds complexity without benefit.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>I hope you found this tutorial useful. To sum up, the strategy pattern gives you a clean way to manage varying behavior without polluting your classes with conditional logic. The context stays simple and stable and the strategies handle the complexity.</p>
<p>We covered the basic pattern, runtime strategy swapping, and enforcing contracts with abstract base classes. As with most design patterns, start simple: even without ABCs, separating your algorithms into their own classes immediately makes your code easier to read, test, and extend.</p>
<p>Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Implement the Observer Pattern in Python ]]>
                </title>
                <description>
                    <![CDATA[ Have you ever wondered how YouTube notifies you when your favorite channel uploads a new video? Or how your email client alerts you when new messages arrive? These are perfect examples of the observer pattern in action. The observer pattern is a desi... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-implement-the-observer-pattern-in-python/</link>
                <guid isPermaLink="false">6994c4a494993ba9dd1ad6ad</guid>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ design patterns ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Bala Priya C ]]>
                </dc:creator>
                <pubDate>Tue, 17 Feb 2026 19:42:28 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1771357332246/45dc3900-04d9-474e-91a8-bac2fec86c2c.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Have you ever wondered how YouTube notifies you when your favorite channel uploads a new video? Or how your email client alerts you when new messages arrive? These are perfect examples of the observer pattern in action.</p>
<p>The observer pattern is a design pattern where an object (called the subject) maintains a list of dependents (called observers) and notifies them automatically when its state changes. It's like having a newsletter subscription: when new content is published, all subscribers get notified.</p>
<p>In this tutorial, you'll learn what the observer pattern is, why it's useful, and how to implement it in Python with practical examples.</p>
<p>You can find the code <a target="_blank" href="https://github.com/balapriyac/python-basics/tree/main/design-patterns/observer">on GitHub</a>.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before we start, make sure you have:</p>
<ul>
<li><p>Python 3.10 or higher installed</p>
</li>
<li><p>Understanding of how Python classes and methods work</p>
</li>
<li><p>Familiarity with object-oriented programming (OOP) concepts</p>
</li>
</ul>
<p>Let's get started!</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-the-observer-pattern">What Is the Observer Pattern?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-a-simple-observer-pattern-example">A Simple Observer Pattern Example</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-handling-unsubscribes">Handling Unsubscribes</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-different-types-of-observers">Different Types of Observers</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-using-abstract-base-classes">Using Abstract Base Classes</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-when-to-use-the-observer-pattern">When to Use the Observer Pattern</a></p>
</li>
</ul>
<h2 id="heading-what-is-the-observer-pattern">What Is the Observer Pattern?</h2>
<p>The observer pattern defines a <a target="_blank" href="https://en.wikipedia.org/wiki/One-to-many_\(data_model\)">one-to-many relationship</a> between objects. <strong>When one object changes state, all its dependents are notified and updated automatically</strong>.</p>
<p>Think of it like a news agency and reporters. When breaking news happens (the subject), the agency notifies all subscribed reporters (observers) immediately. Each reporter can then handle the news in their own way – some might tweet it, others might write articles, and some might broadcast it on TV.</p>
<p>The pattern is useful when:</p>
<ul>
<li><p>You need to notify multiple objects about state changes</p>
</li>
<li><p>You want loose coupling between objects</p>
</li>
<li><p>You don't know how many objects need to be notified in advance</p>
</li>
<li><p>Objects should be able to subscribe and unsubscribe dynamically</p>
</li>
</ul>
<h2 id="heading-a-simple-observer-pattern-example">A Simple Observer Pattern Example</h2>
<p>Let's start with a basic example: a blog that notifies readers when a new article is published.</p>
<p>We'll create a blog (subject) and email subscribers (observers) who get notified automatically when new content is posted.</p>
<p>First, let's build the <code>Blog</code> class that will manage subscribers and send notifications:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Blog</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, name</span>):</span>
        self.name = name
        self._subscribers = []
        self._latest_post = <span class="hljs-literal">None</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">subscribe</span>(<span class="hljs-params">self, subscriber</span>):</span>
        <span class="hljs-string">"""Add a subscriber to the blog"""</span>
        <span class="hljs-keyword">if</span> subscriber <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> self._subscribers:
            self._subscribers.append(subscriber)
            print(<span class="hljs-string">f"✓ <span class="hljs-subst">{subscriber.email}</span> subscribed to <span class="hljs-subst">{self.name}</span>"</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">unsubscribe</span>(<span class="hljs-params">self, subscriber</span>):</span>
        <span class="hljs-string">"""Remove a subscriber from the blog"""</span>
        <span class="hljs-keyword">if</span> subscriber <span class="hljs-keyword">in</span> self._subscribers:
            self._subscribers.remove(subscriber)
            print(<span class="hljs-string">f"✗ <span class="hljs-subst">{subscriber.email}</span> unsubscribed from <span class="hljs-subst">{self.name}</span>"</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">notify_all</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-string">"""Send notifications to all subscribers"""</span>
        print(<span class="hljs-string">f"\nNotifying <span class="hljs-subst">{len(self._subscribers)}</span> subscribers..."</span>)
        <span class="hljs-keyword">for</span> subscriber <span class="hljs-keyword">in</span> self._subscribers:
            subscriber.receive_notification(self.name, self._latest_post)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">publish_post</span>(<span class="hljs-params">self, title</span>):</span>
        <span class="hljs-string">"""Publish a new post and notify subscribers"""</span>
        print(<span class="hljs-string">f"\n📝 <span class="hljs-subst">{self.name}</span> published: '<span class="hljs-subst">{title}</span>'"</span>)
        self._latest_post = title
        self.notify_all()
</code></pre>
<p>The <code>Blog</code> class is our subject. It maintains a list of subscribers in <code>_subscribers</code> and stores the latest post title in <code>_latest_post</code>. The <code>subscribe</code> method adds subscribers to the list, checking for duplicates. The <code>notify_all</code> method loops through all subscribers and calls their <code>receive_notification</code> method. When we call <code>publish_post</code>, it updates the latest post and automatically notifies all subscribers.</p>
<p>Now let's create the observer class that receives notifications:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EmailSubscriber</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, email</span>):</span>
        self.email = email

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">receive_notification</span>(<span class="hljs-params">self, blog_name, post_title</span>):</span>
        print(<span class="hljs-string">f"📧 Email sent to <span class="hljs-subst">{self.email}</span>: New post on <span class="hljs-subst">{blog_name}</span> - '<span class="hljs-subst">{post_title}</span>'"</span>)
</code></pre>
<p>The <code>EmailSubscriber</code> class is our observer. It has one method, <code>receive_notification</code>, which handles incoming notifications from the blog.</p>
<p>Now let's use these classes together:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Create a blog</span>
tech_blog = Blog(<span class="hljs-string">"DevDaily"</span>)

<span class="hljs-comment"># Create subscribers</span>
reader1 = EmailSubscriber(<span class="hljs-string">"anna@example.com"</span>)
reader2 = EmailSubscriber(<span class="hljs-string">"betty@example.com"</span>)
reader3 = EmailSubscriber(<span class="hljs-string">"cathy@example.com"</span>)

<span class="hljs-comment"># Subscribe to the blog</span>
tech_blog.subscribe(reader1)
tech_blog.subscribe(reader2)
tech_blog.subscribe(reader3)

<span class="hljs-comment"># Publish posts</span>
tech_blog.publish_post(<span class="hljs-string">"10 Python Tips for Beginners"</span>)
tech_blog.publish_post(<span class="hljs-string">"Understanding Design Patterns"</span>)
</code></pre>
<p>Output:</p>
<pre><code class="lang-plaintext">✓ anna@example.com subscribed to DevDaily
✓ betty@example.com subscribed to DevDaily
✓ cathy@example.com subscribed to DevDaily

📝 DevDaily published: '10 Python Tips for Beginners'

Notifying 3 subscribers...
📧 Email sent to anna@example.com: New post on DevDaily - '10 Python Tips for Beginners'
📧 Email sent to betty@example.com: New post on DevDaily - '10 Python Tips for Beginners'
📧 Email sent to cathy@example.com: New post on DevDaily - '10 Python Tips for Beginners'

📝 DevDaily published: 'Understanding Design Patterns'

Notifying 3 subscribers...
📧 Email sent to anna@example.com: New post on DevDaily - 'Understanding Design Patterns'
📧 Email sent to betty@example.com: New post on DevDaily - 'Understanding Design Patterns'
📧 Email sent to cathy@example.com: New post on DevDaily - 'Understanding Design Patterns'
</code></pre>
<p>Notice how the <code>Blog</code> class doesn't need to know the details of how each subscriber handles the notification. It just calls their <code>receive_notification</code> method.</p>
<p><strong>Note</strong>: Think of all the examples here as placeholder functions that explain how the observer pattern works. In your projects, you’ll have functions that connect to email and other services.</p>
<h2 id="heading-handling-unsubscribes">Handling Unsubscribes</h2>
<p>In real applications, users need to be able to unsubscribe. Here's how that works:</p>
<pre><code class="lang-python">blog = Blog(<span class="hljs-string">"CodeMaster"</span>)

user1 = EmailSubscriber(<span class="hljs-string">"john@example.com"</span>)
user2 = EmailSubscriber(<span class="hljs-string">"jane@example.com"</span>)

<span class="hljs-comment"># Subscribe users</span>
blog.subscribe(user1)
blog.subscribe(user2)

<span class="hljs-comment"># Publish a post</span>
blog.publish_post(<span class="hljs-string">"Getting Started with Python"</span>)

<span class="hljs-comment"># User1 unsubscribes</span>
blog.unsubscribe(user1)

<span class="hljs-comment"># Publish another post - only user2 gets notified</span>
blog.publish_post(<span class="hljs-string">"Advanced Python Techniques"</span>)
</code></pre>
<p>Output:</p>
<pre><code class="lang-plaintext">✓ john@example.com subscribed to CodeMaster
✓ jane@example.com subscribed to CodeMaster

📝 CodeMaster published: 'Getting Started with Python'

Notifying 2 subscribers...
📧 Email sent to john@example.com: New post on CodeMaster - 'Getting Started with Python'
📧 Email sent to jane@example.com: New post on CodeMaster - 'Getting Started with Python'
✗ john@example.com unsubscribed from CodeMaster

📝 CodeMaster published: 'Advanced Python Techniques'

Notifying 1 subscribers...
📧 Email sent to jane@example.com: New post on CodeMaster - 'Advanced Python Techniques'
</code></pre>
<p>After <code>user1</code> unsubscribes, only <code>user2</code> receives the notification for the second post. The observer pattern makes it easy to add and remove observers dynamically.</p>
<h2 id="heading-different-types-of-observers">Different Types of Observers</h2>
<p>One super useful aspect of the observer pattern is that different observers can react differently to the same event. Let's create a stock price tracker where multiple observer types respond to price changes.</p>
<p>First, let's create the <code>Stock</code> class that will notify observers when the price changes:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Stock</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, symbol, price</span>):</span>
        self.symbol = symbol
        self._price = price
        self._observers = []

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add_observer</span>(<span class="hljs-params">self, observer</span>):</span>
        self._observers.append(observer)
        print(<span class="hljs-string">f"Observer added: <span class="hljs-subst">{observer.__class__.__name__}</span>"</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">remove_observer</span>(<span class="hljs-params">self, observer</span>):</span>
        self._observers.remove(observer)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">notify_observers</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">for</span> observer <span class="hljs-keyword">in</span> self._observers:
            observer.update(self.symbol, self._price)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">set_price</span>(<span class="hljs-params">self, price</span>):</span>
        print(<span class="hljs-string">f"\n <span class="hljs-subst">{self.symbol}</span> price changed: $<span class="hljs-subst">{self._price}</span> → $<span class="hljs-subst">{price}</span>"</span>)
        self._price = price
        self.notify_observers()
</code></pre>
<p>The <code>Stock</code> class maintains the current price and notifies all observers whenever <code>set_price</code> is called.</p>
<p>Now let's create three different observer types that respond differently to price updates:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EmailAlert</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, email</span>):</span>
        self.email = email

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">update</span>(<span class="hljs-params">self, symbol, price</span>):</span>
        print(<span class="hljs-string">f"📧 Sending email to <span class="hljs-subst">{self.email}</span>: <span class="hljs-subst">{symbol}</span> is now $<span class="hljs-subst">{price}</span>"</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SMSAlert</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, phone</span>):</span>
        self.phone = phone

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">update</span>(<span class="hljs-params">self, symbol, price</span>):</span>
        print(<span class="hljs-string">f"📱 Sending SMS to <span class="hljs-subst">{self.phone}</span>: <span class="hljs-subst">{symbol}</span> price update $<span class="hljs-subst">{price}</span>"</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Logger</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">update</span>(<span class="hljs-params">self, symbol, price</span>):</span>
        print(<span class="hljs-string">f"📝 Logging: <span class="hljs-subst">{symbol}</span> = $<span class="hljs-subst">{price}</span> at system time"</span>)
</code></pre>
<p>Each observer has a different implementation of the update method. <code>EmailAlert</code> sends emails, <code>SMSAlert</code> sends text messages, and <code>Logger</code> records the change.</p>
<p>Now let's use them together:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Create a stock</span>
apple_stock = Stock(<span class="hljs-string">"AAPL"</span>, <span class="hljs-number">150.00</span>)

<span class="hljs-comment"># Create different types of observers</span>
email_notifier = EmailAlert(<span class="hljs-string">"investor@example.com"</span>)
sms_notifier = SMSAlert(<span class="hljs-string">"+1234567890"</span>)
price_logger = Logger()

<span class="hljs-comment"># Add all observers</span>
apple_stock.add_observer(email_notifier)
apple_stock.add_observer(sms_notifier)
apple_stock.add_observer(price_logger)

<span class="hljs-comment"># Update the stock price</span>
apple_stock.set_price(<span class="hljs-number">155.50</span>)
apple_stock.set_price(<span class="hljs-number">152.25</span>)
</code></pre>
<p>Output:</p>
<pre><code class="lang-plaintext">Observer added: EmailAlert
Observer added: SMSAlert
Observer added: Logger

 AAPL price changed: $150.0 → $155.5
📧 Sending email to investor@example.com: AAPL is now $155.5
📱 Sending SMS to +1234567890: AAPL price update $155.5
📝 Logging: AAPL = $155.5 at system time

 AAPL price changed: $155.5 → $152.25
📧 Sending email to investor@example.com: AAPL is now $152.25
📱 Sending SMS to +1234567890: AAPL price update $152.25
📝 Logging: AAPL = $152.25 at system time
</code></pre>
<p>The <code>Stock</code> class doesn't care what each observer does. It simply calls <code>update</code> on each one and passes the necessary data. You can mix and match observers however you want.</p>
<h2 id="heading-using-abstract-base-classes">Using Abstract Base Classes</h2>
<p>To enforce a consistent interface across all observers, we can use Python's <a target="_blank" href="https://docs.python.org/3/library/abc.html">Abstract Base Classes</a>. This guarantees type safety.</p>
<p>First, let's create the base classes that define our interface:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> abc <span class="hljs-keyword">import</span> ABC, abstractmethod

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Subject</span>(<span class="hljs-params">ABC</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
        self._observers = []

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">attach</span>(<span class="hljs-params">self, observer</span>):</span>
        <span class="hljs-keyword">if</span> observer <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> self._observers:
            self._observers.append(observer)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">detach</span>(<span class="hljs-params">self, observer</span>):</span>
        self._observers.remove(observer)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">notify</span>(<span class="hljs-params">self, data</span>):</span>
        <span class="hljs-keyword">for</span> observer <span class="hljs-keyword">in</span> self._observers:
            observer.update(data)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Observer</span>(<span class="hljs-params">ABC</span>):</span>
<span class="hljs-meta">    @abstractmethod</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">update</span>(<span class="hljs-params">self, data</span>):</span>
        <span class="hljs-keyword">pass</span>
</code></pre>
<p>The <code>Subject</code> class provides standard observer management methods. The <code>Observer</code> class defines the interface with the <code>@abstractmethod</code> decorator ensuring all observers implement update.</p>
<p>Now let's create an order system that uses these base classes:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OrderSystem</span>(<span class="hljs-params">Subject</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
        super().__init__()
        self._order_id = <span class="hljs-literal">None</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">place_order</span>(<span class="hljs-params">self, order_id, items</span>):</span>
        print(<span class="hljs-string">f"\n🛒 Order #<span class="hljs-subst">{order_id}</span> placed with <span class="hljs-subst">{len(items)}</span> items"</span>)
        self._order_id = order_id
        self.notify({<span class="hljs-string">"order_id"</span>: order_id, <span class="hljs-string">"items"</span>: items})
</code></pre>
<p>The <code>OrderSystem</code> inherits from <code>Subject</code> and can manage observers without implementing that logic itself.</p>
<p>Next, let's create concrete observers for different departments:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">InventoryObserver</span>(<span class="hljs-params">Observer</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">update</span>(<span class="hljs-params">self, data</span>):</span>
        print(<span class="hljs-string">f"📦 Inventory: Updating stock for order #<span class="hljs-subst">{data[<span class="hljs-string">'order_id'</span>]}</span>"</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ShippingObserver</span>(<span class="hljs-params">Observer</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">update</span>(<span class="hljs-params">self, data</span>):</span>
        print(<span class="hljs-string">f"🚚 Shipping: Preparing shipment for order #<span class="hljs-subst">{data[<span class="hljs-string">'order_id'</span>]}</span>"</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BillingObserver</span>(<span class="hljs-params">Observer</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">update</span>(<span class="hljs-params">self, data</span>):</span>
        print(<span class="hljs-string">f"💳 Billing: Processing payment for order #<span class="hljs-subst">{data[<span class="hljs-string">'order_id'</span>]}</span>"</span>)
</code></pre>
<p>Each observer <em>must</em> implement the <code>update</code> method. Now let's put it all together:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Create the order system</span>
order_system = OrderSystem()

<span class="hljs-comment"># Create observers</span>
inventory = InventoryObserver()
shipping = ShippingObserver()
billing = BillingObserver()

<span class="hljs-comment"># Attach observers</span>
order_system.attach(inventory)
order_system.attach(shipping)
order_system.attach(billing)

<span class="hljs-comment"># Place an order</span>
order_system.place_order(<span class="hljs-string">"ORD-12345"</span>, [<span class="hljs-string">"Laptop"</span>, <span class="hljs-string">"Mouse"</span>, <span class="hljs-string">"Keyboard"</span>])
</code></pre>
<p>Output:</p>
<pre><code class="lang-plaintext">🛒 Order #ORD-12345 placed with 3 items
📦 Inventory: Updating stock for order #ORD-12345
🚚 Shipping: Preparing shipment for order #ORD-12345
💳 Billing: Processing payment for order #ORD-12345
</code></pre>
<p>Using abstract base classes provides type safety and ensures all observers follow the same interface.</p>
<h2 id="heading-when-to-use-the-observer-pattern">When to Use the Observer Pattern</h2>
<p>The observer pattern is suiatble for:</p>
<ul>
<li><p>Event-driven systems – GUI frameworks, game engines, or any system where actions trigger updates elsewhere.</p>
</li>
<li><p>Real-time notifications – Chat apps, social media feeds, stock tickers, or push notification systems.</p>
</li>
<li><p>Decoupled architecture – When you want the subject independent of its observers for flexibility.</p>
</li>
<li><p>Multiple listeners – When multiple objects need to react to the same event differently.</p>
</li>
</ul>
<p>Avoid the Observer Pattern when you have simple one-to-one relationships, or when performance is critical with many observers (because notification overhead can be significant).</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The observer pattern creates a clean separation between objects that produce events and objects that respond to them. It promotes loose coupling – the subject doesn't need to know anything about its observers except that they have an update method.</p>
<p>We've covered the basic implementation, handling subscriptions, using different observer types, and abstract base classes. Start simple with the basic subject-observer relationship and add complexity only when needed.</p>
<p>Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use the Factory Pattern in Python - A Practical Guide ]]>
                </title>
                <description>
                    <![CDATA[ Design patterns are proven solutions to common problems in software development. If you've ever found yourself writing repetitive object creation code or struggling to manage different types of objects, the factory pattern might be exactly what you n... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-the-factory-pattern-in-python-a-practical-guide/</link>
                <guid isPermaLink="false">6989f75b7982b0d48a3c2c48</guid>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ design patterns ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Bala Priya C ]]>
                </dc:creator>
                <pubDate>Mon, 09 Feb 2026 15:03:55 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1770649418899/f26d3d70-a909-4d8f-92f5-7f263c64f9fe.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Design patterns are proven solutions to common problems in software development. If you've ever found yourself writing repetitive object creation code or struggling to manage different types of objects, the <strong>factory pattern</strong> might be exactly what you need.</p>
<p>In this tutorial, you'll learn what the factory pattern is, why it's useful, and how to implement it in Python. We'll build practical examples that show you when and how to use this pattern in real-world applications.</p>
<p>You can find the code <a target="_blank" href="https://github.com/balapriyac/python-basics/tree/main/design-patterns/factory">on GitHub</a>.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before we start, make sure you have:</p>
<ul>
<li><p>Python 3.10 or higher installed</p>
</li>
<li><p>Understanding of Python classes and methods</p>
</li>
<li><p>Familiarity with <a target="_blank" href="https://www.youtube.com/watch?v=Ej_02ICOIgs">object-oriented programming</a> (OOP) concepts</p>
</li>
</ul>
<p>Let’s get started!</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-the-factory-pattern">What Is the Factory Pattern?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-a-simple-factory-example">A Simple Factory Example</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-using-a-dictionary-for-cleaner-code">Using a Dictionary for Cleaner Code</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-factory-pattern-with-parameters">Factory Pattern with Parameters</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-using-abstract-base-classes">Using Abstract Base Classes</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-a-more-helpful-example-database-connection-factory">A More Helpful Example: Database Connection Factory</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-when-to-use-the-factory-pattern">When to Use the Factory Pattern</a></p>
</li>
</ul>
<h2 id="heading-what-is-the-factory-pattern">What Is the Factory Pattern?</h2>
<p>The factory pattern is a creational design pattern that <strong>provides an interface for creating objects without specifying their exact classes</strong>. Instead of calling a constructor directly, you call a factory method that decides which class to instantiate.</p>
<p>Think of it like ordering food at a restaurant. You don't go into the kitchen and make the food yourself. You tell the waiter what you want, and the kitchen (the factory) creates it for you. You get your meal without worrying about the recipe or cooking process.</p>
<p>The factory pattern is useful when:</p>
<ul>
<li><p>You have multiple related classes and need to decide which one to instantiate at runtime</p>
</li>
<li><p>Object creation logic is complex and you want to encapsulate it</p>
</li>
<li><p>You want to make your code more maintainable and testable</p>
</li>
</ul>
<h2 id="heading-a-simple-factory-example">A Simple Factory Example</h2>
<p>Let's start with a basic example. Say you're building a notification system that can send messages via email, SMS, or push notifications.</p>
<p>Without a factory, you might write code like this everywhere in your application:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Bad approach - tight coupling</span>
<span class="hljs-keyword">if</span> notification_type == <span class="hljs-string">"email"</span>:
    notifier = EmailNotifier()
<span class="hljs-keyword">elif</span> notification_type == <span class="hljs-string">"sms"</span>:
    notifier = SMSNotifier()
<span class="hljs-keyword">elif</span> notification_type == <span class="hljs-string">"push"</span>:
    notifier = PushNotifier()
</code></pre>
<p>This gets messy quickly. Let's use a factory instead:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EmailNotifier</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">send</span>(<span class="hljs-params">self, message</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">f"Sending email: <span class="hljs-subst">{message}</span>"</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SMSNotifier</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">send</span>(<span class="hljs-params">self, message</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">f"Sending SMS: <span class="hljs-subst">{message}</span>"</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PushNotifier</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">send</span>(<span class="hljs-params">self, message</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">f"Sending push notification: <span class="hljs-subst">{message}</span>"</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NotificationFactory</span>:</span>
<span class="hljs-meta">    @staticmethod</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_notifier</span>(<span class="hljs-params">notifier_type</span>):</span>
        <span class="hljs-keyword">if</span> notifier_type == <span class="hljs-string">"email"</span>:
            <span class="hljs-keyword">return</span> EmailNotifier()
        <span class="hljs-keyword">elif</span> notifier_type == <span class="hljs-string">"sms"</span>:
            <span class="hljs-keyword">return</span> SMSNotifier()
        <span class="hljs-keyword">elif</span> notifier_type == <span class="hljs-string">"push"</span>:
            <span class="hljs-keyword">return</span> PushNotifier()
        <span class="hljs-keyword">else</span>:
            <span class="hljs-keyword">raise</span> ValueError(<span class="hljs-string">f"Unknown notifier type: <span class="hljs-subst">{notifier_type}</span>"</span>)
</code></pre>
<p>In this code, we define three notifier classes, each with a send method.</p>
<p><strong>Note</strong>: In a real application, these would have different implementations for sending notifications.</p>
<p>The <code>NotificationFactory</code> class has a <a target="_blank" href="https://docs.python.org/3/library/functions.html#staticmethod">static method</a> called <code>create_notifier</code>. This is our factory method. It takes a string parameter and returns the appropriate notifier object.</p>
<p>The <code>@staticmethod</code> decorator means we can call this method without creating an instance of the factory. We just use <code>NotificationFactory.create_notifier()</code>.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Using the factory</span>
notifier = NotificationFactory.create_notifier(<span class="hljs-string">"email"</span>)
result = notifier.send(<span class="hljs-string">"Hello, World!"</span>)
</code></pre>
<p>Now, whenever we need a notifier, we call the factory instead of instantiating classes directly. This centralizes our object creation logic in one place.</p>
<h2 id="heading-using-a-dictionary-for-cleaner-code">Using a Dictionary for Cleaner Code</h2>
<p>The if-elif chain in our factory can get unwieldy as we add more notifier types. Let's refactor using a dictionary:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NotificationFactory</span>:</span>
    notifier_types = {
        <span class="hljs-string">"email"</span>: EmailNotifier,
        <span class="hljs-string">"sms"</span>: SMSNotifier,
        <span class="hljs-string">"push"</span>: PushNotifier
    }

<span class="hljs-meta">    @staticmethod</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_notifier</span>(<span class="hljs-params">notifier_type</span>):</span>
        notifier_class = NotificationFactory.notifier_types.get(notifier_type)
        <span class="hljs-keyword">if</span> notifier_class:
            <span class="hljs-keyword">return</span> notifier_class()
        <span class="hljs-keyword">else</span>:
            <span class="hljs-keyword">raise</span> ValueError(<span class="hljs-string">f"Unknown notifier type: <span class="hljs-subst">{notifier_type}</span>"</span>)
</code></pre>
<p>This approach is much cleaner. We store a dictionary that maps strings to class objects and <em>not</em> instances. The keys are notifier type names, and the values are the actual class references.</p>
<p>The <code>get</code> method retrieves the class from the dictionary. If the key doesn't exist, it returns <code>None</code>. We then instantiate the class by calling it with parentheses: <code>notifier_class()</code>.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Test with different types</span>
email_notifier = NotificationFactory.create_notifier(<span class="hljs-string">"email"</span>)
sms_notifier = NotificationFactory.create_notifier(<span class="hljs-string">"sms"</span>)
push_notifier = NotificationFactory.create_notifier(<span class="hljs-string">"push"</span>)
</code></pre>
<p>This makes adding new notifier types easier. You just add another entry to the dictionary.</p>
<h2 id="heading-factory-pattern-with-parameters">Factory Pattern with Parameters</h2>
<p>Real-world objects often need configuration. Let's extend our factory to handle notifiers that require initialization parameters.</p>
<p>We'll create a document generator that produces different file formats with custom settings:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PDFDocument</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, title, author</span>):</span>
        self.title = title
        self.author = author
        self.format = <span class="hljs-string">"PDF"</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">generate</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">f"Generating <span class="hljs-subst">{self.format}</span>: '<span class="hljs-subst">{self.title}</span>' by <span class="hljs-subst">{self.author}</span>"</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WordDocument</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, title, author</span>):</span>
        self.title = title
        self.author = author
        self.format = <span class="hljs-string">"DOCX"</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">generate</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">f"Generating <span class="hljs-subst">{self.format}</span>: '<span class="hljs-subst">{self.title}</span>' by <span class="hljs-subst">{self.author}</span>"</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MarkdownDocument</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, title, author</span>):</span>
        self.title = title
        self.author = author
        self.format = <span class="hljs-string">"MD"</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">generate</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">f"Generating <span class="hljs-subst">{self.format}</span>: '<span class="hljs-subst">{self.title}</span>' by <span class="hljs-subst">{self.author}</span>"</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DocumentFactory</span>:</span>
    document_types = {
        <span class="hljs-string">"pdf"</span>: PDFDocument,
        <span class="hljs-string">"word"</span>: WordDocument,
        <span class="hljs-string">"markdown"</span>: MarkdownDocument
    }

<span class="hljs-meta">    @staticmethod</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_document</span>(<span class="hljs-params">doc_type, title, author</span>):</span>
        document_class = DocumentFactory.document_types.get(doc_type)
        <span class="hljs-keyword">if</span> document_class:
            <span class="hljs-keyword">return</span> document_class(title, author)
        <span class="hljs-keyword">else</span>:
            <span class="hljs-keyword">raise</span> ValueError(<span class="hljs-string">f"Unknown document type: <span class="hljs-subst">{doc_type}</span>"</span>)
</code></pre>
<p>The key difference here is that our factory method now accepts additional parameters.</p>
<p>The <code>create_document</code> method takes <code>doc_type</code>, <code>title</code>, and <code>author</code> as arguments. When we instantiate the class, we pass the <code>title</code> and <code>author</code> to the <code>create_document</code> constructor: <code>document_class(title, author)</code>.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Create different documents with parameters</span>
pdf = DocumentFactory.create_document(<span class="hljs-string">"pdf"</span>, <span class="hljs-string">"Python Guide"</span>, <span class="hljs-string">"Tutorial Team"</span>)
word = DocumentFactory.create_document(<span class="hljs-string">"word"</span>, <span class="hljs-string">"Meeting Notes"</span>, <span class="hljs-string">"Grace Dev"</span>)
markdown = DocumentFactory.create_document(<span class="hljs-string">"markdown"</span>, <span class="hljs-string">"README"</span>, <span class="hljs-string">"DevTeam"</span>)
</code></pre>
<p>This lets us create fully configured objects through the factory while keeping the creation logic centralized.</p>
<h2 id="heading-using-abstract-base-classes">Using Abstract Base Classes</h2>
<p>To make our factory more robust, we can use Python's <a target="_blank" href="https://docs.python.org/3/library/abc.html">Abstract Base Classes (ABC)</a> to enforce a common interface.</p>
<p>Let's create a super simple payment processing system:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> abc <span class="hljs-keyword">import</span> ABC, abstractmethod

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PaymentProcessor</span>(<span class="hljs-params">ABC</span>):</span>
<span class="hljs-meta">    @abstractmethod</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">process_payment</span>(<span class="hljs-params">self, amount</span>):</span>
        <span class="hljs-keyword">pass</span>

<span class="hljs-meta">    @abstractmethod</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">refund</span>(<span class="hljs-params">self, transaction_id</span>):</span>
        <span class="hljs-keyword">pass</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CreditCardProcessor</span>(<span class="hljs-params">PaymentProcessor</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">process_payment</span>(<span class="hljs-params">self, amount</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">f"Processing $<span class="hljs-subst">{amount}</span> via Credit Card"</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">refund</span>(<span class="hljs-params">self, transaction_id</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">f"Refunding credit card transaction <span class="hljs-subst">{transaction_id}</span>"</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PayPalProcessor</span>(<span class="hljs-params">PaymentProcessor</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">process_payment</span>(<span class="hljs-params">self, amount</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">f"Processing $<span class="hljs-subst">{amount}</span> via PayPal"</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">refund</span>(<span class="hljs-params">self, transaction_id</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">f"Refunding PayPal transaction <span class="hljs-subst">{transaction_id}</span>"</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PaymentFactory</span>:</span>
    processors = {
        <span class="hljs-string">"credit_card"</span>: CreditCardProcessor,
        <span class="hljs-string">"paypal"</span>: PayPalProcessor
    }

<span class="hljs-meta">    @staticmethod</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_processor</span>(<span class="hljs-params">processor_type</span>):</span>
        processor_class = PaymentFactory.processors.get(processor_type)
        <span class="hljs-keyword">if</span> processor_class:
            <span class="hljs-keyword">return</span> processor_class()
        <span class="hljs-keyword">else</span>:
            <span class="hljs-keyword">raise</span> ValueError(<span class="hljs-string">f"Unknown processor type: <span class="hljs-subst">{processor_type}</span>"</span>)
</code></pre>
<p>Here, the <code>PaymentProcessor</code> class defines an interface that <em>all</em> payment processors must implement. The <code>@abstractmethod</code> decorator marks methods that subclasses must override.</p>
<p>You cannot instantiate <code>PaymentProcessor</code> directly. It only serves as a blueprint. All concrete processors (<code>CreditCardProcessor</code>, <code>PayPalProcessor</code>) must implement both <code>process_payment</code> and <code>refund</code> methods. If they don't, Python will raise an error. This guarantees that any object created by our factory will have the expected methods, making our code more predictable and safer.</p>
<p>You can use the factory like so:</p>
<pre><code class="lang-python">processor = PaymentFactory.create_processor(<span class="hljs-string">"paypal"</span>)
</code></pre>
<h2 id="heading-a-more-helpful-example-database-connection-factory">A More Helpful Example: Database Connection Factory</h2>
<p>Let's build something practical: a factory that creates different database connection objects based on configuration.</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MySQLConnection</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, host, database</span>):</span>
        self.host = host
        self.database = database
        self.connection_type = <span class="hljs-string">"MySQL"</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">connect</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">f"Connected to <span class="hljs-subst">{self.connection_type}</span> at <span class="hljs-subst">{self.host}</span>/<span class="hljs-subst">{self.database}</span>"</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">execute_query</span>(<span class="hljs-params">self, query</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">f"Executing on MySQL: <span class="hljs-subst">{query}</span>"</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PostgreSQLConnection</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, host, database</span>):</span>
        self.host = host
        self.database = database
        self.connection_type = <span class="hljs-string">"PostgreSQL"</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">connect</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">f"Connected to <span class="hljs-subst">{self.connection_type}</span> at <span class="hljs-subst">{self.host}</span>/<span class="hljs-subst">{self.database}</span>"</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">execute_query</span>(<span class="hljs-params">self, query</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">f"Executing on PostgreSQL: <span class="hljs-subst">{query}</span>"</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SQLiteConnection</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, host, database</span>):</span>
        self.host = host
        self.database = database
        self.connection_type = <span class="hljs-string">"SQLite"</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">connect</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">f"Connected to <span class="hljs-subst">{self.connection_type}</span> at <span class="hljs-subst">{self.host}</span>/<span class="hljs-subst">{self.database}</span>"</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">execute_query</span>(<span class="hljs-params">self, query</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">f"Executing on SQLite: <span class="hljs-subst">{query}</span>"</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DatabaseFactory</span>:</span>
    db_types = {
        <span class="hljs-string">"mysql"</span>: MySQLConnection,
        <span class="hljs-string">"postgresql"</span>: PostgreSQLConnection,
        <span class="hljs-string">"sqlite"</span>: SQLiteConnection
    }

<span class="hljs-meta">    @staticmethod</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_connection</span>(<span class="hljs-params">db_type, host, database</span>):</span>
        db_class = DatabaseFactory.db_types.get(db_type)
        <span class="hljs-keyword">if</span> db_class:
            <span class="hljs-keyword">return</span> db_class(host, database)
        <span class="hljs-keyword">else</span>:
            <span class="hljs-keyword">raise</span> ValueError(<span class="hljs-string">f"Unknown database type: <span class="hljs-subst">{db_type}</span>"</span>)

<span class="hljs-meta">    @staticmethod</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_from_config</span>(<span class="hljs-params">config</span>):</span>
        <span class="hljs-string">"""Create a database connection from a configuration dictionary"""</span>
        <span class="hljs-keyword">return</span> DatabaseFactory.create_connection(
            config[<span class="hljs-string">"type"</span>],
            config[<span class="hljs-string">"host"</span>],
            config[<span class="hljs-string">"database"</span>]
        )
</code></pre>
<p>This example shows a more realistic use case. We have multiple database connection classes, each with the same interface but different implementations.</p>
<p>The factory has two creation methods: <code>create_connection</code> for direct parameters and <code>create_from_config</code> for configuration dictionaries.</p>
<p>The <code>create_from_config</code> method is particularly useful because it lets you load database settings from a config file or environment variables and create the appropriate connection object.</p>
<p>This pattern makes it easy to switch between different databases without changing your application code. You just change the configuration as shown:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Use with direct parameters</span>
db1 = DatabaseFactory.create_connection(<span class="hljs-string">"mysql"</span>, <span class="hljs-string">"localhost"</span>, <span class="hljs-string">"myapp_db"</span>)
print(db1.connect())
print(db1.execute_query(<span class="hljs-string">"SELECT * FROM users"</span>))

<span class="hljs-comment"># Use with configuration dictionary</span>
config = {
    <span class="hljs-string">"type"</span>: <span class="hljs-string">"postgresql"</span>,
    <span class="hljs-string">"host"</span>: <span class="hljs-string">"db.example.com"</span>,
    <span class="hljs-string">"database"</span>: <span class="hljs-string">"production_db"</span>
}
db2 = DatabaseFactory.create_from_config(config)
</code></pre>
<h2 id="heading-when-to-use-the-factory-pattern">When to Use the Factory Pattern</h2>
<p>The factory pattern is useful when you have the following:</p>
<ol>
<li><p><strong>Multiple related classes</strong>: When you have several classes that share a common interface but have different implementations (like the payment processors or database connections we had in the examples).</p>
</li>
<li><p><strong>Runtime decisions</strong>: When you need to decide which class to instantiate based on user input, configuration, or other runtime conditions.</p>
</li>
<li><p><strong>Complex object creation</strong>: When creating an object involves multiple steps or requires specific logic that you want to encapsulate.</p>
</li>
</ol>
<p>However, don't use the factory pattern when:</p>
<ul>
<li><p>You only have one or two simple classes</p>
</li>
<li><p>Object creation is straightforward with no special logic</p>
</li>
<li><p>The added abstraction makes your code harder to understand</p>
</li>
</ul>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>The factory pattern is a useful tool for managing object creation in Python. It helps you write cleaner, more maintainable code by centralizing creation logic and decoupling your code from specific class implementations. We've covered:</p>
<ul>
<li><p>Basic factory implementation with simple examples</p>
</li>
<li><p>Using dictionaries for cleaner factory code</p>
</li>
<li><p>Passing parameters to factory-created objects</p>
</li>
<li><p>Using abstract base classes for cleaner interfaces</p>
</li>
</ul>
<p>The key takeaway is this: <strong>whenever you find yourself writing repetitive object creation code or need to decide which class to instantiate at runtime, consider using the factory pattern</strong>. Start simple and add complexity only when needed. The basic dictionary-based factory is often all you need for most applications.</p>
<p>Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How the Factory and Abstract Factory Design Patterns Work in Flutter ]]>
                </title>
                <description>
                    <![CDATA[ In software development, particularly object-oriented programming and design, object creation is a common task. And how you manage this process can impact your app's flexibility, scalability, and maintainability. Creational design patterns govern how... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-the-factory-and-abstract-factory-design-patterns-work-in-flutter/</link>
                <guid isPermaLink="false">6978f477116625d0304ed264</guid>
                
                    <category>
                        <![CDATA[ design patterns ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Factory Design Pattern ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Mobile Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Mobile apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Developer ]]>
                    </category>
                
                    <category>
                        <![CDATA[ OOPS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Object Oriented Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ design principles ]]>
                    </category>
                
                    <category>
                        <![CDATA[ object oriented design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Dart ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Abstract Factory Patterns ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oluwaseyi Fatunmole ]]>
                </dc:creator>
                <pubDate>Tue, 27 Jan 2026 17:23:03 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769533734673/8b5ad88a-13d2-4fec-969b-55fd854df5c1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In software development, particularly object-oriented programming and design, object creation is a common task. And how you manage this process can impact your app's flexibility, scalability, and maintainability.</p>
<p>Creational design patterns govern how classes and objects are created in a systematic and scalable way. They provide blueprints for creating objects so you don't repeat code. They also keep your system consistent and makes your app easy to extend.</p>
<p>There are five major Creational Design patterns:</p>
<ol>
<li><p><strong>Singleton:</strong> Ensures a class has only one instance and provides a global point of access to it.</p>
</li>
<li><p><strong>Factory Method</strong>: Provides an interface for creating objects but lets subclasses decide which class to instantiate.</p>
</li>
<li><p><strong>Abstract Factory</strong>: Creates families of related objects without specifying their concrete classes.</p>
</li>
<li><p><strong>Builder</strong>: Allows you to construct complex objects step by step, separating construction from representation.</p>
</li>
<li><p><strong>Prototype</strong>: Creates new objects by cloning existing ones, rather than creating from scratch.</p>
</li>
</ol>
<p>Each of these patterns solves specific problems around object creation, depending on the complexity and scale of your application.</p>
<p>In this tutorial, I'll explain what Creational Design Patterns are and how they work. We'll focus on two primary patterns: the Factory and Abstract Factory patterns.</p>
<p>Many people mix these two up, so here we'll explore:</p>
<ol>
<li><p>How each pattern works</p>
</li>
<li><p>Practical examples in Flutter</p>
</li>
<li><p>Applications, best practices, and usage</p>
</li>
</ol>
<p>By the end, you'll understand when to use Factory, when to switch to Abstract Factory, and how to structure your Flutter apps for scalability and maintainability.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-how-the-factory-pattern-works-in-flutter">How the Factory Pattern Works in Flutter</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-step-1-define-the-product-and-abstract-creator">Step 1: Define the Product and Abstract Creator</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-implement-concrete-products">Step 2: Implement Concrete Products</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-create-the-factory">Step 3: Create the Factory</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-use-the-factory">Step 4: Use the Factory</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-factory-pattern-for-security-checks">Factory Pattern for Security Checks</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-the-abstract-factory-pattern-works-in-flutter">How the Abstract Factory Pattern Works in Flutter</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-step-1-define-abstract-product-interfaces">Step 1: Define Abstract Product Interfaces</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-implement-platform-specific-products">Step 2: Implement Platform-Specific Products</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-define-the-abstract-factory-interface">Step 3: Define the Abstract Factory Interface</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-implement-platform-specific-factories">Step 4: Implement Platform Specific Factories</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-5-client-code-using-abstract-factory">Step 5: Client Code Using Abstract Factory</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before diving into this tutorial, you should have:</p>
<ul>
<li><p>a basic understanding of the Dart programming language</p>
</li>
<li><p>familiarity with Object-Oriented Programming (OOP) concepts (particularly classes, inheritance, and abstract classes)</p>
</li>
<li><p>basic knowledge of Flutter development (helpful but not required)</p>
</li>
<li><p>an understanding of interfaces and polymorphism</p>
</li>
<li><p>and experience creating and instantiating classes in Dart.</p>
</li>
</ul>
<h2 id="heading-how-the-factory-pattern-works-in-flutter">How the Factory Pattern Works in Flutter</h2>
<p>You'll typically use the Factory Pattern when you want to manage data sets that might be related, but only for a single type of object.</p>
<p>Let's say you want to manage themes for Android and iOS. Using the Factory Pattern allows you to encapsulate object creation and keep your app modular. We'll build this step by step so you can see how the pattern works.</p>
<h3 id="heading-step-1-define-the-product-and-abstract-creator">Step 1: Define the Product and Abstract Creator</h3>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppTheme</span> </span>{
  <span class="hljs-built_in">String?</span> data;
  AppTheme({<span class="hljs-keyword">this</span>.data});
}

<span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ApplicationThemeData</span> </span>{
  Future&lt;AppTheme&gt; getApplicationTheme();
}
</code></pre>
<p>Here, <code>AppTheme</code> is a simple data class that holds theme information. This represents the product our factory will create. <code>ApplicationThemeData</code> serves as an abstract base class. This abstraction is crucial because it defines a contract that all concrete theme implementations must follow.</p>
<p>By requiring a <code>getApplicationTheme()</code> method, we ensure consistency across different platforms.</p>
<h3 id="heading-step-2-implement-concrete-products">Step 2: Implement Concrete Products</h3>
<p>Now we create platform-specific implementations that provide actual theme data.</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AndroidAppTheme</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ApplicationThemeData</span> </span>{
  <span class="hljs-meta">@override</span>
  Future&lt;AppTheme&gt; getApplicationTheme() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">return</span> AppTheme(data: <span class="hljs-string">"Here is android theme"</span>);
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IOSThemeData</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ApplicationThemeData</span> </span>{
  <span class="hljs-meta">@override</span>
  Future&lt;AppTheme&gt; getApplicationTheme() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">return</span> AppTheme(data: <span class="hljs-string">"This is IOS theme data"</span>);
  }
}
</code></pre>
<p>The concrete implementations, <code>AndroidAppTheme</code> and <code>IOSThemeData</code>, extend the abstract class and provide platform-specific theme data. Each returns an <code>AppTheme</code> object with content tailored to its respective platform.</p>
<h3 id="heading-step-3-create-the-factory">Step 3: Create the Factory</h3>
<p>The factory encapsulates the object creation logic, so client code doesn't need to know which specific theme class it's working with.</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ThemeFactory</span> </span>{
  ThemeFactory({<span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.theme});
  ApplicationThemeData theme;

  loadTheme() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> theme.getApplicationTheme();
  }
}
</code></pre>
<p><code>ThemeFactory</code> acts as the factory itself. It accepts any <code>ApplicationThemeData</code> implementation and provides a unified <code>loadTheme()</code> method. This encapsulates the object creation logic cleanly.</p>
<h3 id="heading-step-4-use-the-factory">Step 4: Use the Factory</h3>
<p>Finally, we use the factory in our application code.</p>
<pre><code class="lang-dart">ThemeFactory(
  theme: Platform.isAndroid ? AndroidAppTheme() : IOSThemeData()
).loadTheme();
</code></pre>
<p>Here, you choose a theme (Android or iOS) and get the corresponding <code>AppTheme</code>. This approach is simple and effective when you only care about one functionality, like loading a theme.</p>
<p>The beauty of this pattern is that the client code remains clean and doesn't need to change if you add new platforms later.</p>
<h2 id="heading-factory-pattern-for-security-checks">Factory Pattern for Security Checks</h2>
<p>Another excellent use case for the Factory Pattern is when implementing security checks during your application bootstrap.</p>
<p>For instance, Android and iOS require different logic for internal security. Android might check for developer mode or rooted devices, while iOS checks for jailbroken devices. This scenario is a perfect example of when to apply the Factory Pattern, as it allows you to encapsulate platform-specific security logic cleanly and maintainably. Let's implement this step by step.</p>
<h3 id="heading-step-1-define-security-check-result-and-abstract-checker">Step 1: Define Security Check Result and Abstract Checker</h3>
<p>First, we need a standardized way to communicate security check outcomes and a contract for performing security checks.</p>
<pre><code class="lang-dart"><span class="hljs-comment">// Base security check result class</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SecurityCheckResult</span> </span>{
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">bool</span> isSecure;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String</span> message;

  SecurityCheckResult({<span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.isSecure, <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.message});
}

<span class="hljs-comment">// Abstract security checker</span>
<span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SecurityChecker</span> </span>{
  Future&lt;SecurityCheckResult&gt; performSecurityCheck();
}
</code></pre>
<p>The <code>SecurityCheckResult</code> class provides a standardized way to communicate security check outcomes across platforms.</p>
<p>It contains a boolean flag indicating security status and a descriptive message for the user. The abstract <code>SecurityChecker</code> class defines the contract that all platform-specific security implementations must follow.</p>
<p>This ensures that, regardless of the platform, we can always call <code>performSecurityCheck()</code> and receive a consistent result type.</p>
<h3 id="heading-step-2-implement-platform-specific-security-checkers">Step 2: Implement Platform-Specific Security Checkers</h3>
<p>Now we create the actual security checking implementations for each platform.</p>
<pre><code class="lang-dart"><span class="hljs-comment">// Android-specific security implementation</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AndroidSecurityChecker</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">SecurityChecker</span> </span>{
  <span class="hljs-meta">@override</span>
  Future&lt;SecurityCheckResult&gt; performSecurityCheck() <span class="hljs-keyword">async</span> {
    <span class="hljs-built_in">bool</span> isRooted = <span class="hljs-keyword">await</span> checkIfDeviceIsRooted();
    <span class="hljs-keyword">if</span> (isRooted) {
      <span class="hljs-keyword">return</span> SecurityCheckResult(
        isSecure: <span class="hljs-keyword">false</span>,
        message: <span class="hljs-string">"Device is rooted. App cannot run on rooted devices."</span>
      );
    }

    <span class="hljs-built_in">bool</span> isDeveloperMode = <span class="hljs-keyword">await</span> checkDeveloperMode();
    <span class="hljs-keyword">if</span> (isDeveloperMode) {
      <span class="hljs-keyword">return</span> SecurityCheckResult(
        isSecure: <span class="hljs-keyword">false</span>,
        message: <span class="hljs-string">"Developer mode is enabled. Please disable it to continue."</span>
      );
    }

    <span class="hljs-keyword">return</span> SecurityCheckResult(
      isSecure: <span class="hljs-keyword">true</span>,
      message: <span class="hljs-string">"Device security check passed."</span>
    );
  }

  Future&lt;<span class="hljs-built_in">bool</span>&gt; checkIfDeviceIsRooted() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>; 
  }

  Future&lt;<span class="hljs-built_in">bool</span>&gt; checkDeveloperMode() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>; <span class="hljs-comment">// Placeholder</span>
  }
}

<span class="hljs-comment">// iOS-specific security implementation</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IOSSecurityChecker</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">SecurityChecker</span> </span>{
  <span class="hljs-meta">@override</span>
  Future&lt;SecurityCheckResult&gt; performSecurityCheck() <span class="hljs-keyword">async</span> {
    <span class="hljs-built_in">bool</span> isJailbroken = <span class="hljs-keyword">await</span> checkIfDeviceIsJailbroken();

    <span class="hljs-keyword">if</span> (isJailbroken) {
      <span class="hljs-keyword">return</span> SecurityCheckResult(
        isSecure: <span class="hljs-keyword">false</span>,
        message: <span class="hljs-string">"Device is jailbroken. App cannot run on jailbroken devices."</span>
      );
    }

    <span class="hljs-keyword">return</span> SecurityCheckResult(
      isSecure: <span class="hljs-keyword">true</span>,
      message: <span class="hljs-string">"Device security check passed."</span>
    );
  }

  Future&lt;<span class="hljs-built_in">bool</span>&gt; checkIfDeviceIsJailbroken() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>; 
  }
}
</code></pre>
<p>The Android implementation focuses on detecting rooted devices and developer mode, which are common security concerns on Android.</p>
<p>A rooted device has elevated permissions that could allow malicious apps to access sensitive data, while developer mode can expose debugging interfaces.</p>
<p>The iOS implementation checks for jailbroken devices, which is the iOS equivalent of rooting. Jailbroken devices bypass Apple's security restrictions and can pose similar security risks.</p>
<h3 id="heading-step-3-create-the-security-factory">Step 3: Create the Security Factory</h3>
<p>The factory wraps the chosen security checker and provides a clean interface for running checks.</p>
<pre><code class="lang-dart"><span class="hljs-comment">// Security Factory</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SecurityCheckFactory</span> </span>{
  SecurityCheckFactory({<span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.checker});
  SecurityChecker checker;

  Future&lt;SecurityCheckResult&gt; runSecurityCheck() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> checker.performSecurityCheck();
  }
}
</code></pre>
<p>The <code>SecurityCheckFactory</code> provides a simple interface that accepts any <code>SecurityChecker</code> implementation. This means your app initialization code doesn't need to know about platform-specific security details – it just calls <code>runSecurityCheck()</code> and handles the result.</p>
<h3 id="heading-step-4-use-the-security-factory-in-app-bootstrap">Step 4: Use the Security Factory in App Bootstrap</h3>
<p>Finally, we integrate the security factory into our app's initialization process.</p>
<pre><code class="lang-dart"><span class="hljs-comment">// In your app's bootstrap/initialization</span>
Future&lt;<span class="hljs-keyword">void</span>&gt; initializeApp() <span class="hljs-keyword">async</span> {
  <span class="hljs-keyword">final</span> securityFactory = SecurityCheckFactory(
    checker: Platform.isAndroid 
      ? AndroidSecurityChecker() 
      : IOSSecurityChecker()
  );

  <span class="hljs-keyword">final</span> result = <span class="hljs-keyword">await</span> securityFactory.runSecurityCheck();

  <span class="hljs-keyword">if</span> (!result.isSecure) {
    <span class="hljs-comment">// Show error dialog and prevent app from continuing</span>
    showSecurityErrorDialog(result.message);
    <span class="hljs-keyword">return</span>;
  }

  <span class="hljs-comment">// Continue with normal app initialization</span>
  runApp(MyApp());
}
</code></pre>
<p>This usage example demonstrates how the Factory Pattern makes your app initialization code clean and maintainable.</p>
<p>The platform detection happens in one place, the factory handles the creation of the appropriate checker, and your code simply deals with the standardized result.</p>
<p><strong>Key takeaway:</strong> Factory is great when you need one type of object, but you want to abstract away the creation logic.</p>
<h2 id="heading-how-the-abstract-factory-pattern-works-in-flutter">How the Abstract Factory Pattern Works in Flutter</h2>
<p>The Abstract Factory Pattern comes into play when you have more than two data sets for comparison, and each set includes multiple functionalities.</p>
<p>For example, imagine you now want to manage themes, widgets, and architecture for Android, iOS, and Linux. Managing this with just a Factory becomes messy, so Abstract Factory provides a structured way to handle multiple related objects for different platforms.</p>
<p>So let's see how you can handle this using the abstract factory method.</p>
<h3 id="heading-step-1-define-abstract-product-interfaces">Step 1: Define Abstract Product Interfaces</h3>
<p>Before we dive into this implementation, it's important to understand what abstract product interfaces are. An abstract product interface is essentially a contract that defines what methods a product must implement, without specifying how they're implemented.</p>
<p>Think of it as a blueprint that ensures all related products share a common structure. In our case, we're defining three core functionalities that every platform must provide:</p>
<ol>
<li><p>Theme management</p>
</li>
<li><p>Widget handling</p>
</li>
<li><p>Architecture configuration.</p>
</li>
</ol>
<p>By creating these abstract interfaces first, we establish a consistent API that all platform-specific implementations will follow.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ThemeManager</span> </span>{
  Future&lt;<span class="hljs-built_in">String</span>&gt; getTheme();
}

<span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WidgetHandler</span> </span>{
  Future&lt;<span class="hljs-built_in">bool</span>&gt; getWidget();
}

<span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ArchitechtureHandler</span> </span>{
  Future&lt;<span class="hljs-built_in">String</span>&gt; getArchitechture();
}
</code></pre>
<p>Here, we’re defining three base functionalities that every platform will implement: theme, widgets, and architecture.</p>
<p>Each interface declares a single method that returns platform-specific information.</p>
<p>The <code>ThemeManager</code> retrieves theme data, <code>WidgetHandler</code> determines widget compatibility, and <code>ArchitechtureHandler</code> provides architecture details.</p>
<h3 id="heading-step-2-implement-platform-specific-products">Step 2: Implement Platform-Specific Products</h3>
<p>Now that we have our abstract interfaces defined, we need to create concrete implementations for each platform. This step is where we provide the actual, platform-specific behavior for each product type. Think of this as filling in the blueprint with real details.</p>
<p>While the abstract interfaces told us what methods we need, these concrete classes tell us how those methods behave on each specific platform. Each platform (Android, iOS, Linux) will have its own unique implementation of themes, widgets, and architecture.</p>
<h4 id="heading-android">Android:</h4>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AndroidThemeManager</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ThemeManager</span> </span>{
  <span class="hljs-meta">@override</span>
  Future&lt;<span class="hljs-built_in">String</span>&gt; getTheme() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Android Theme"</span>;
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AndroidWidgetHandler</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">WidgetHandler</span> </span>{
  <span class="hljs-meta">@override</span>
  Future&lt;<span class="hljs-built_in">bool</span>&gt; getWidget() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AndroidArchitechtureHandler</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ArchitechtureHandler</span> </span>{
  <span class="hljs-meta">@override</span>
  Future&lt;<span class="hljs-built_in">String</span>&gt; getArchitechture() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Android Architecture"</span>;
  }
}
</code></pre>
<p>For Android, we're creating three specific product classes. The <code>AndroidThemeManager</code> returns Material Design theme data, the <code>AndroidWidgetHandler</code> returns true to indicate that Android supports home screen widgets, and the <code>AndroidArchitechtureHandler</code> provides information about Android's architecture (which could include details about ARM, x86, or other processor architectures).</p>
<h4 id="heading-ios">iOS:</h4>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IOSThemeManager</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ThemeManager</span> </span>{
  <span class="hljs-meta">@override</span>
  Future&lt;<span class="hljs-built_in">String</span>&gt; getTheme() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"IOS Theme"</span>;
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IOSWidgetHandler</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">WidgetHandler</span> </span>{
  <span class="hljs-meta">@override</span>
  Future&lt;<span class="hljs-built_in">bool</span>&gt; getWidget() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IOSArchitechtureHandler</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ArchitechtureHandler</span> </span>{
  <span class="hljs-meta">@override</span>
  Future&lt;<span class="hljs-built_in">String</span>&gt; getArchitechture() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"iOS Architecture"</span>;
  }
}
</code></pre>
<p>The iOS implementations follow the same structure but provide iOS-specific values. Notice that <code>IOSWidgetHandler</code> returns false, this could represent a scenario where certain widget features aren't available or behave differently on iOS compared to Android.</p>
<h4 id="heading-linux">Linux:</h4>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LinuxThemeManager</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ThemeManager</span> </span>{
  <span class="hljs-meta">@override</span>
  Future&lt;<span class="hljs-built_in">String</span>&gt; getTheme() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Linux Theme"</span>;
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LinuxWidgetHandler</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">WidgetHandler</span> </span>{
  <span class="hljs-meta">@override</span>
  Future&lt;<span class="hljs-built_in">bool</span>&gt; getWidget() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LinuxArchitechtureHandler</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ArchitechtureHandler</span> </span>{
  <span class="hljs-meta">@override</span>
  Future&lt;<span class="hljs-built_in">String</span>&gt; getArchitechture() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Linux Architecture"</span>;
  }
}
</code></pre>
<p>Similarly, Linux gets its own set of implementations, providing Linux-specific theme data and architecture information.</p>
<h3 id="heading-step-3-define-the-abstract-factory-interface">Step 3: Define the Abstract Factory Interface</h3>
<p>With our product classes ready, we now need to create the factory that will produce them.</p>
<p>The abstract factory interface is the master blueprint that declares which products our factory must be able to create. This interface doesn't create anything itself, it simply declares that any concrete factory must provide methods to create all three product types (theme, widget, and architecture handlers). This ensures that, regardless of which platform factory we use, we can always access all three functionalities.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppFactory</span> </span>{
  ThemeManager themeManager();
  WidgetHandler widgetManager();
  ArchitechtureHandler architechtureHandler();
}
</code></pre>
<p>Here, we define a factory blueprint. Any platform specific factory will have to implement all three functionalities. This guarantees consistency: every platform will have all three capabilities available.</p>
<h3 id="heading-step-4-implement-platform-specific-factories">Step 4: Implement Platform Specific Factories</h3>
<p>This is where everything comes together. We're now creating the actual factories that will produce the platform-specific products we defined earlier. Each factory is responsible for creating all the related products for its platform. The key advantage here is encapsulation: the factory knows how to create all the related objects for a platform, and it ensures they're compatible with each other. For example, <code>AndroidFactory</code> creates Android-specific theme managers, widget handlers, and architecture handlers that all work together seamlessly.</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AndroidFactory</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">AppFactory</span> </span>{
  <span class="hljs-meta">@override</span>
  ThemeManager themeManager() =&gt; AndroidThemeManager();

  <span class="hljs-meta">@override</span>
  WidgetHandler widgetManager() =&gt; AndroidWidgetHandler();

  <span class="hljs-meta">@override</span>
  ArchitechtureHandler architechtureHandler() =&gt; AndroidArchitechtureHandler();
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IOSFactory</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">AppFactory</span> </span>{
  <span class="hljs-meta">@override</span>
  ThemeManager themeManager() =&gt; IOSThemeManager();

  <span class="hljs-meta">@override</span>
  WidgetHandler widgetManager() =&gt; IOSWidgetHandler();

  <span class="hljs-meta">@override</span>
  ArchitechtureHandler architechtureHandler() =&gt; IOSArchitechtureHandler();
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LinuxFactory</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">AppFactory</span> </span>{
  <span class="hljs-meta">@override</span>
  ThemeManager themeManager() =&gt; LinuxThemeManager();

  <span class="hljs-meta">@override</span>
  WidgetHandler widgetManager() =&gt; LinuxWidgetHandler();

  <span class="hljs-meta">@override</span>
  ArchitechtureHandler architechtureHandler() =&gt; LinuxArchitechtureHandler();
}
</code></pre>
<p>Each concrete factory (AndroidFactory, IOSFactory, LinuxFactory) implements all three methods from the <code>AppFactory</code> interface. When you call <code>themeManager()</code> on <code>AndroidFactory</code>, you get an <code>AndroidThemeManager</code>. When you call it on <code>IOSFactory</code>, you get an <code>IOSThemeManager</code>. The same pattern applies to all products.</p>
<h3 id="heading-step-5-client-code-using-abstract-factory">Step 5: Client Code Using Abstract Factory</h3>
<p>Finally, we create the client code that uses our abstract factory. This is the layer that your application will actually interact with. The beauty of this pattern is that the client code doesn't need to know anything about the specific platform implementations, it just works with the abstract factory interface.</p>
<p>The <code>AppBaseFactory</code> class accepts any factory that implements <code>AppFactory</code> and provides a simple method to initialize all platform settings. The <code>CheckDevice</code> class determines which factory to use based on the current platform, completely abstracting this decision away from the rest of your application.</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppBaseFactory</span> </span>{
  AppBaseFactory({<span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.<span class="hljs-keyword">factory</span>});
  AppFactory <span class="hljs-keyword">factory</span>;

  getAppSettings() {
    <span class="hljs-keyword">factory</span>
      ..architechtureHandler()
      ..themeManager()
      ..widgetManager();
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CheckDevice</span> </span>{
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">get</span>() {
    <span class="hljs-keyword">if</span> (Platform.isAndroid) <span class="hljs-keyword">return</span> AndroidFactory();
    <span class="hljs-keyword">if</span> (Platform.isIOS) <span class="hljs-keyword">return</span> IOSFactory();
    <span class="hljs-keyword">if</span> (Platform.isLinux) <span class="hljs-keyword">return</span> LinuxFactory();
    <span class="hljs-keyword">throw</span> UnsupportedError(<span class="hljs-string">"Platform not supported"</span>);
  }
}

<span class="hljs-comment">// Usage</span>
AppBaseFactory(<span class="hljs-keyword">factory</span>: CheckDevice.<span class="hljs-keyword">get</span>()).getAppSettings();
</code></pre>
<p>Here's what's happening in this code:</p>
<p>The <code>AppBaseFactory</code> class acts as a wrapper around any <code>AppFactory</code> implementation. It provides a convenient <code>getAppSettings()</code> method that initializes all three components (architecture handler, theme manager, and widget manager) using Dart's cascade notation.</p>
<p>The <code>CheckDevice</code> class contains the platform detection logic. Its static <code>get()</code> method checks the current platform and returns the appropriate factory. This centralizes all platform detection in one place. When you call <code>AppBaseFactory(factory: CheckDevice.get()).getAppSettings()</code>, the code automatically detects your platform, creates the right factory, and initializes all platform-specific components, all without the calling code needing to know any platform-specific details.</p>
<p>Each platform factory produces all related products. The client only interacts with <code>AppBaseFactory</code>, remaining unaware of the internal implementation. This ensures your code is scalable, maintainable, and consistent.</p>
<h2 id="heading-real-world-application-payment-provider-management">Real-World Application: Payment Provider Management</h2>
<p>Another good use case for abstract factory is when you need to switch between multiple payment providers in your application and you only want to expose the necessary functionality to the client (presentation layer).</p>
<p>The abstract factory design pattern properly helps you manage this scenario in terms of concrete implementation, encapsulation, clean code, separation of concerns, and proper code structure and management. For example, you might support Stripe, PayPal, and Flutterwave in your application.</p>
<p>Each provider requires different initialization, transaction processing, and webhook handling. By using the Abstract Factory pattern, you can create a consistent interface for all payment operations while keeping provider-specific details encapsulated within their respective factory implementations.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>You should now feel more comfortable deciding when to use the Factory design pattern vs the Abstract Factory design pattern.</p>
<p>Understanding the factory and abstract factory patterns and their usages properly will help with object creation based on the particular use case you are trying to implement.</p>
<p>The Factory Pattern is ideal when you need one product and want to encapsulate creation logic while the Abstract Factory Pattern works well when you have multiple related products across platforms, need consistency, and want scalability. Using these patterns will help you write clean, maintainable, and scalable Flutter apps.</p>
<p>They give you a systematic approach to object creation and prevent messy, hard-to-maintain code as your app grows.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use the Singleton Design Pattern in Flutter: Lazy, Eager, and Factory Variations ]]>
                </title>
                <description>
                    <![CDATA[ In software engineering, sometimes you need only one instance of a class across your entire application. Creating multiple instances in such cases can lead to inconsistent behavior, wasted memory, or resource conflicts. The Singleton Design Pattern i... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-the-singleton-design-pattern-in-flutter-lazy-eager-and-factory-variations/</link>
                <guid isPermaLink="false">69740b7bc3e68b8de44a179f</guid>
                
                    <category>
                        <![CDATA[ Singleton Design Pattern ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Object Oriented Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ design patterns ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ood ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Dart ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software architecture ]]>
                    </category>
                
                    <category>
                        <![CDATA[ flutter development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Factory Design Pattern ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Mobile Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oluwaseyi Fatunmole ]]>
                </dc:creator>
                <pubDate>Fri, 23 Jan 2026 23:59:55 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769212761076/11d41d2a-8efa-4ddb-9ee2-218f5be00d9f.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In software engineering, sometimes you need only one instance of a class across your entire application. Creating multiple instances in such cases can lead to inconsistent behavior, wasted memory, or resource conflicts.</p>
<p>The Singleton Design Pattern is a creational design pattern that solves this problem by ensuring that a class has exactly one instance and provides a global point of access to it.</p>
<p>This pattern is widely used in mobile apps, backend systems, and Flutter applications for managing shared resources such as:</p>
<ul>
<li><p>Database connections</p>
</li>
<li><p>API clients</p>
</li>
<li><p>Logging services</p>
</li>
<li><p>Application configuration</p>
</li>
<li><p>Security checks during app bootstrap</p>
</li>
</ul>
<p>In this article, we'll explore what the Singleton pattern is, how to implement it in Flutter/Dart, its variations (eager, lazy, and factory), and physical examples. By the end, you'll understand the proper way to use this pattern effectively and avoid common pitfalls.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-the-singleton-pattern">What is the Singleton Pattern?</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-when-to-use-the-singleton-pattern">When to Use the Singleton Pattern</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-a-singleton-class">How to Create a Singleton Class</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-eager-singleton">Eager Singleton</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-lazy-singleton">Lazy Singleton</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-choosing-between-eager-and-lazy">Choosing Between Eager and Lazy</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-factory-constructors-in-the-singleton-pattern">Factory Constructors in the Singleton Pattern</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-are-factory-constructors">What Are Factory Constructors?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-implementing-singleton-with-factory-constructor">Implementing Singleton with Factory Constructor</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-when-not-to-use-a-singleton">When Not to Use a Singleton</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-why-singletons-can-be-problematic">Why Singletons Can Be Problematic</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-scenarios-where-you-should-avoid-singletons">Scenarios Where You Should Avoid Singletons</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-general-guidelines">General Guidelines</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before diving into this tutorial, you should have:</p>
<ol>
<li><p>Basic understanding of the Dart programming language</p>
</li>
<li><p>Familiarity with Object-Oriented Programming (OOP) concepts, particularly classes and constructors</p>
</li>
<li><p>Basic knowledge of Flutter development (helpful but not required)</p>
</li>
<li><p>Understanding of static variables and methods in Dart</p>
</li>
<li><p>Familiarity with the concept of class instantiation</p>
</li>
</ol>
<h2 id="heading-what-is-the-singleton-pattern">What is the Singleton Pattern?</h2>
<p>The Singleton pattern is a creational design pattern that ensures a class has only one instance and that there is a global point of access to the instance.</p>
<p>Again, this is especially powerful when managing shared resources across an application.</p>
<h3 id="heading-when-to-use-the-singleton-pattern">When to Use the Singleton Pattern</h3>
<p>You should use a Singleton when you are designing parts of your system that must exist once, such as:</p>
<ol>
<li><p>Global app state (user session, auth token, app config)</p>
</li>
<li><p>Shared services (logger, API client, database connection)</p>
</li>
<li><p>Resource heavy logic (encryption handlers, ML models, cache manager)</p>
</li>
<li><p>Application boot security (run platform-specific root/jailbreak checks)</p>
</li>
</ol>
<p>For example, in a Flutter app, Android may check developer mode or root status, while iOS checks jailbroken device state. A Singleton security class is a perfect way to enforce that these checks run once globally during app startup.</p>
<h2 id="heading-how-to-create-a-singleton-class">How to Create a Singleton Class</h2>
<p>We have two major ways of creating a singleton class:</p>
<ol>
<li><p>Eager Instantiation</p>
</li>
<li><p>Lazy Instantiation</p>
</li>
</ol>
<h3 id="heading-eager-singleton">Eager Singleton</h3>
<p>This is where the Singleton is created at load time, whether it's used or not.</p>
<p>In this case, the instance of the singleton class as well as any initialization logic runs at load time, regardless of when this class is actually needed or used. Here's how it works:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EagerSingleton</span> </span>{
  EagerSingleton._internal();
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> EagerSingleton _instance = EagerSingleton._internal();

  <span class="hljs-keyword">static</span> EagerSingleton <span class="hljs-keyword">get</span> instance =&gt; _instance;

  <span class="hljs-keyword">void</span> sayHello() =&gt; <span class="hljs-built_in">print</span>(<span class="hljs-string">"Hello from Eager Singleton"</span>);
}

<span class="hljs-comment">//usage</span>
<span class="hljs-keyword">void</span> main() {
  <span class="hljs-comment">// Accessing the singleton globally</span>
  EagerSingleton.instance.sayHello();
}
</code></pre>
<h4 id="heading-how-the-eager-singleton-works">How the Eager Singleton Works</h4>
<p>Let's break down what's happening in this implementation:</p>
<p>First, <code>EagerSingleton._internal()</code> is a private named constructor (notice the underscore prefix). This prevents external code from creating new instances using <code>EagerSingleton()</code>. The only way to get an instance is through the controlled mechanism we're about to define.</p>
<p>Next, <code>static final EagerSingleton _instance = EagerSingleton._internal();</code> is the key line. This creates the single instance immediately when the class is first loaded into memory. Because it's <code>static final</code>, it belongs to the class itself (not any particular instance) and can only be assigned once. The instance is created right here, at declaration time.</p>
<p>The <code>static EagerSingleton get instance =&gt; _instance;</code> getter provides global access to that single instance. Whenever you call <code>EagerSingleton.instance</code> anywhere in your code, you're getting the exact same object that was created when the class loaded.</p>
<p>Finally, <code>sayHello()</code> is just a regular method to demonstrate that the singleton works. You could replace this with any business logic your singleton needs to perform.</p>
<p>When you run the code in <code>main()</code>, the class loads, the instance is created immediately, and <code>EagerSingleton.instance.sayHello()</code> accesses that pre-created instance to call the method.</p>
<h4 id="heading-pros">Pros:</h4>
<ol>
<li><p>This is simple and thread safe, meaning it's not affected by concurrency, especially when your app runs on multithreads.</p>
</li>
<li><p>It's ideal if the instance is lightweight and may be accessed frequently.</p>
</li>
</ol>
<h4 id="heading-cons">Cons:</h4>
<ol>
<li>If this instance is never used through the runtime, it results in wasted memory and could impact application performance.</li>
</ol>
<h3 id="heading-lazy-singleton">Lazy Singleton</h3>
<p>In this case, the singleton instance is only created when the class is called or needed in runtime. Here, a trigger needs to happen before the instance is created. Let's see an example:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LazySingleton</span> </span>{
  LazySingleton._internal(); 
  <span class="hljs-keyword">static</span> LazySingleton? _instance;

  <span class="hljs-keyword">static</span> LazySingleton <span class="hljs-keyword">get</span> instance {
    _instance ??= LazySingleton._internal();
    <span class="hljs-keyword">return</span> _instance!;
  }

  <span class="hljs-keyword">void</span> sayHello() =&gt; <span class="hljs-built_in">print</span>(<span class="hljs-string">"Hello from LazySingleton"</span>);
}

<span class="hljs-comment">//usage </span>
<span class="hljs-keyword">void</span> main() {
  <span class="hljs-comment">// Accessing the singleton globally</span>
  LazySingleton.instance.sayHello();
}
</code></pre>
<h4 id="heading-how-the-lazy-singleton-works">How the Lazy Singleton Works</h4>
<p>The lazy implementation differs from eager in one crucial way: timing.</p>
<p>Again, <code>LazySingleton._internal()</code> is a private constructor that prevents external instantiation.</p>
<p>But notice that <code>static LazySingleton? _instance;</code> is declared as nullable and not initialized. Unlike the eager version, no instance is created at load time. The variable simply exists as <code>null</code> until it's needed.</p>
<p>The magic happens in the getter: <code>_instance ??= LazySingleton._internal();</code> uses Dart's null-aware assignment operator. This line says "if <code>_instance</code> is null, create a new instance and assign it. Otherwise, keep the existing one." This is the lazy initialization: the instance is only created the first time someone accesses it.</p>
<p>The first time you call <code>LazySingleton.instance</code>, <code>_instance</code> is null, so a new instance is created. Every subsequent call finds that <code>_instance</code> already exists, so it just returns that same instance.</p>
<p>The <code>return _instance!;</code> uses the null assertion operator because we know <code>_instance</code> will never be null at this point (we just ensured it's not null in the previous line).</p>
<p>This approach saves memory because if you never call <code>LazySingleton.instance</code> in your app, the instance never gets created.</p>
<h4 id="heading-pros-1">Pros:</h4>
<ol>
<li><p>Saves application memory, as it only creates what is needed in runtime.</p>
</li>
<li><p>Avoids memory leaks.</p>
</li>
<li><p>Is ideal for resource heavy objects while considering application performance.</p>
</li>
</ol>
<h4 id="heading-cons-1">Cons:</h4>
<ol>
<li>Could be difficult to manage in multithreaded environments, as you have to ensure thread safety while following this pattern.</li>
</ol>
<h3 id="heading-choosing-between-eager-and-lazy">Choosing Between Eager and Lazy</h3>
<p>Now that we've broken down these two major types of singleton instantiation, it's worthy of note that you'll need to be intentional while deciding whether to create a singleton the eager or lazy way. Your use case/context should help you determine what singleton pattern you need to apply during object creation.</p>
<p>As an engineer, you need to ask yourself these questions when using a singleton for object creation:</p>
<ol>
<li><p>Do I need this class instantiated when the app loads?</p>
</li>
<li><p>Based on the user journey, will this class always be needed during every session?</p>
</li>
<li><p>Can a user journey be completed without needing to call any logic in this class?</p>
</li>
</ol>
<p>These three questions will determine what pattern (eager or lazy) you should use to fulfill best practices while maintaining scalability and high performance in your application.</p>
<h2 id="heading-factory-constructors-in-the-singleton-pattern">Factory Constructors in the Singleton Pattern</h2>
<p>Applying factory constructors in the Singleton pattern can be powerful if you use them properly. But first, let's understand what factory constructors are.</p>
<h3 id="heading-what-are-factory-constructors">What Are Factory Constructors?</h3>
<p>A factory constructor in Dart is a special type of constructor that doesn't always create a new instance of its class. Unlike regular constructors that must return a new instance, factory constructors can:</p>
<ol>
<li><p>Return an existing instance (perfect for singletons)</p>
</li>
<li><p>Return a subclass instance</p>
</li>
<li><p>Apply logic before deciding what to return</p>
</li>
<li><p>Perform validation or initialization before returning an object</p>
</li>
</ol>
<p>The <code>factory</code> keyword tells Dart that this constructor has the flexibility to return any instance of the class (or its subtypes), not necessarily a fresh one.</p>
<h3 id="heading-implementing-singleton-with-factory-constructor">Implementing Singleton with Factory Constructor</h3>
<p>This allows you to apply initialization logic while your class instance is being created before returning the instance.</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FactoryLazySingleton</span> </span>{
  FactoryLazySingleton._internal();
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> FactoryLazySingleton _instance = FactoryLazySingleton._internal();

  <span class="hljs-keyword">static</span> FactoryLazySingleton <span class="hljs-keyword">get</span> instance =&gt; _instance;

  <span class="hljs-keyword">factory</span> FactoryLazySingleton() {
    <span class="hljs-comment">// Your logic runs here</span>
    <span class="hljs-built_in">print</span>(<span class="hljs-string">"Factory constructor called"</span>);
    <span class="hljs-keyword">return</span> _instance;
  }
}
</code></pre>
<h4 id="heading-how-the-factory-constructor-singleton-works">How the Factory Constructor Singleton Works</h4>
<p>This implementation combines aspects of both eager and lazy patterns with additional control.</p>
<p>The <code>FactoryLazySingleton._internal()</code> private constructor and <code>static final _instance</code> create an eager singleton. The instance is created immediately when the class loads.</p>
<p>The <code>static get instance</code> provides the traditional singleton access pattern we've seen before.</p>
<p>But the interesting part is the <code>factory FactoryLazySingleton()</code> constructor. This is a public constructor that looks like a normal constructor call, but behaves differently. When you call <code>FactoryLazySingleton()</code>, instead of creating a new instance, it runs whatever logic you've placed inside (in this case, a print statement), then returns the existing <code>_instance</code>.</p>
<p>This pattern is powerful because:</p>
<ol>
<li><p>You can log when someone tries to create an instance</p>
</li>
<li><p>You can validate conditions before returning the instance</p>
</li>
<li><p>You can apply configuration based on parameters passed to the factory</p>
</li>
<li><p>You can choose to return different singleton instances based on conditions</p>
</li>
</ol>
<p>For example, you might have different configuration singletons for development vs production:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">factory</span> FactoryLazySingleton({<span class="hljs-built_in">bool</span> isProduction = <span class="hljs-keyword">false</span>}) {
  <span class="hljs-keyword">if</span> (isProduction) {
    <span class="hljs-comment">// Apply production configuration</span>
    _instance.configure(productionSettings);
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-comment">// Apply development configuration</span>
    _instance.configure(devSettings);
  }
  <span class="hljs-keyword">return</span> _instance;
}
</code></pre>
<h4 id="heading-pros-2">Pros</h4>
<ol>
<li><p>You can add logic before returning an instance</p>
</li>
<li><p>You can cache or reuse the same object</p>
</li>
<li><p>You can dynamically return a subtype if needed</p>
</li>
<li><p>You avoid unnecessary instantiation</p>
</li>
<li><p>You can inject configuration or environment logic</p>
</li>
</ol>
<h4 id="heading-cons-2">Cons</h4>
<ol>
<li><p>Adds slight complexity compared to simple getter access</p>
</li>
<li><p>The factory constructor syntax might confuse developers unfamiliar with the pattern</p>
</li>
<li><p>If overused with complex logic, it can make debugging harder</p>
</li>
<li><p>Can create misleading code where <code>FactoryLazySingleton()</code> looks like it creates a new instance but doesn't</p>
</li>
</ol>
<h2 id="heading-when-not-to-use-a-singleton">When Not to Use a Singleton</h2>
<p>While singletons are powerful, they're not always the right solution. Understanding when to avoid them is just as important as knowing when to use them.</p>
<h3 id="heading-why-singletons-can-be-problematic">Why Singletons Can Be Problematic</h3>
<p>Singletons create global state, which can make your application harder to reason about and test. They introduce tight coupling between components that shouldn't necessarily know about each other, and they can make it difficult to isolate components for unit testing.</p>
<h3 id="heading-scenarios-where-you-should-avoid-singletons">Scenarios Where You Should Avoid Singletons</h3>
<p>Avoid using the Singleton pattern if:</p>
<h4 id="heading-you-need-multiple-independent-instances">You need multiple independent instances</h4>
<p>If different parts of your app need their own separate configurations or states, singletons force you into a one-size-fits-all approach.</p>
<p>For example, if you're building a multi-tenant application where each tenant needs isolated data, a singleton would cause data to bleed between tenants.</p>
<p><strong>Alternative</strong>: Use dependency injection to pass different instances to different parts of your app. Each component receives the specific instance it needs through its constructor or a service locator.</p>
<pre><code class="lang-dart"><span class="hljs-comment">// Instead of singleton</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserRepository</span> </span>{
  <span class="hljs-keyword">final</span> DatabaseConnection db;
  UserRepository(<span class="hljs-keyword">this</span>.db); 
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-keyword">final</span> dbForTenantA = DatabaseConnection(tenantId: <span class="hljs-string">'A'</span>);
<span class="hljs-keyword">final</span> dbForTenantB = DatabaseConnection(tenantId: <span class="hljs-string">'B'</span>);
<span class="hljs-keyword">final</span> repoA = UserRepository(dbForTenantA);
<span class="hljs-keyword">final</span> repoB = UserRepository(dbForTenantB);
</code></pre>
<h4 id="heading-your-architecture-avoids-shared-global-state">Your architecture avoids shared global state</h4>
<p>Modern architectural patterns like BLoC, Provider, or Riverpod in Flutter specifically aim to avoid global mutable state. Singletons work against these patterns by reintroducing global state.</p>
<p><strong>Alternative</strong>: Use state management solutions designed for Flutter. Provider, Riverpod, BLoC, or GetX offer better ways to share data across your app while maintaining testability and avoiding tight coupling.</p>
<pre><code class="lang-dart"><span class="hljs-comment">// Using Provider instead of singleton</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppConfig</span> </span>{
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String</span> apiUrl;
  AppConfig(<span class="hljs-keyword">this</span>.apiUrl);
}

<span class="hljs-comment">// Provide it at the top level</span>
<span class="hljs-keyword">void</span> main() {
  runApp(
    Provider&lt;AppConfig&gt;(
      create: (_) =&gt; AppConfig(<span class="hljs-string">'https://api.example.com'</span>),
      child: MyApp(),
    ),
  );
}

<span class="hljs-comment">// Access it anywhere in the widget tree</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyWidget</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">final</span> config = Provider.of&lt;AppConfig&gt;(context);

  }
}
</code></pre>
<h4 id="heading-it-forces-tight-coupling-between-unrelated-classes">It forces tight coupling between unrelated classes</h4>
<p>When multiple unrelated classes depend on the same singleton, they become indirectly coupled. Changes to the singleton affect all these classes, making the codebase fragile and hard to refactor.</p>
<p><strong>Alternative</strong>: Use interfaces and dependency injection. Define what behavior you need through an interface, then inject implementations. This way, classes depend on abstractions, not concrete singletons.</p>
<pre><code class="lang-dart"><span class="hljs-comment">// Define an interface</span>
<span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Logger</span> </span>{
  <span class="hljs-keyword">void</span> log(<span class="hljs-built_in">String</span> message);
}

<span class="hljs-comment">// Implementation</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ConsoleLogger</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Logger</span> </span>{
  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> log(<span class="hljs-built_in">String</span> message) =&gt; <span class="hljs-built_in">print</span>(message);
}

<span class="hljs-comment">// Classes depend on the interface, not a singleton</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PaymentService</span> </span>{
  <span class="hljs-keyword">final</span> Logger logger;
  PaymentService(<span class="hljs-keyword">this</span>.logger);

  <span class="hljs-keyword">void</span> processPayment() {
    logger.log(<span class="hljs-string">'Processing payment'</span>);
  }
}

<span class="hljs-comment">// Easy to test with mock</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MockLogger</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Logger</span> </span>{
  <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">String</span>&gt; logs = [];
  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> log(<span class="hljs-built_in">String</span> message) =&gt; logs.add(message);
}
</code></pre>
<h4 id="heading-you-need-clean-isolated-testing">You need clean, isolated testing</h4>
<p>Singletons maintain state between tests, causing test pollution where one test affects another. This makes tests unreliable and order-dependent.</p>
<p><strong>Alternative</strong>: Use dependency injection and create fresh instances for each test. Most testing frameworks support this pattern, allowing you to inject mocks or fakes easily.</p>
<pre><code class="lang-dart"><span class="hljs-comment">// Testable code</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OrderService</span> </span>{
  <span class="hljs-keyword">final</span> PaymentProcessor processor;
  OrderService(<span class="hljs-keyword">this</span>.processor);
}

<span class="hljs-comment">// In tests</span>
<span class="hljs-keyword">void</span> main() {
  test(<span class="hljs-string">'processes order successfully'</span>, () {
    <span class="hljs-keyword">final</span> mockProcessor = MockPaymentProcessor();
    <span class="hljs-keyword">final</span> service = OrderService(mockProcessor); 

  });
}
</code></pre>
<h3 id="heading-general-guidelines">General Guidelines</h3>
<p>Use singletons sparingly and only when you truly need exactly one instance of something for the entire application lifecycle. Good candidates include logging systems, application-level configuration, and hardware interface managers.</p>
<p>For most other cases, prefer dependency injection, state management solutions, or simply passing instances where needed. These approaches make your code more flexible, testable, and maintainable.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The Singleton pattern is a powerful creational tool, but like every tool, you should use it strategically.</p>
<p>Overusing singletons can make apps tightly coupled, hard to test, and less maintainable.</p>
<p>But when used correctly, the Singleton pattern helps you save memory, enforce consistency, and control object lifecycle beautifully.</p>
<p>The key is understanding your specific use case and choosing the right implementation approach – whether eager, lazy, or factory-based – that best serves your application's needs while maintaining clean, testable code.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use the Optimistic UI Pattern with the useOptimistic() Hook in React ]]>
                </title>
                <description>
                    <![CDATA[ Have you ever clicked a Like icon on a social media app and noticed the count jumps instantly? The colour of the icon changes at the same time, even before the server finishes the action. Now imagine you hit the same Like button, but it takes its swe... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-the-optimistic-ui-pattern-with-the-useoptimistic-hook-in-react/</link>
                <guid isPermaLink="false">693c5d28a2bfa1537f407a65</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ design patterns ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Tapas Adhikary ]]>
                </dc:creator>
                <pubDate>Fri, 12 Dec 2025 18:21:28 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1765561440350/c3546e6c-8b23-476a-86d4-b63fd2cb9f6c.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Have you ever clicked a <code>Like</code> icon on a social media app and noticed the count jumps instantly? The colour of the icon changes at the same time, even before the server finishes the action.</p>
<p>Now imagine you hit the same Like button, but it takes its sweet time in making the server call, performing the DB updates, and getting you the response back to update the state of the Like button.</p>
<p>Which experience would you like the most? You are most likely to select the first scenario. We all love “instant feedback”. The magic of instant feedback is powered by a pattern called the <code>Optimistic UI Pattern</code>.</p>
<p>In this article, we will uncover:</p>
<ul>
<li><p>What does Optimistic UI really mean?</p>
</li>
<li><p>Why does it massively improve the user experience?</p>
</li>
<li><p>How does React 19’s new useOptimistic() hook make it easier than ever?</p>
</li>
<li><p>How to implement a real-world scenario using the Optimistic Pattern</p>
</li>
<li><p>A bunch of use cases where you will be able to use this pattern.</p>
</li>
</ul>
<p>By the end, you will be proactively thinking of using this design pattern to improve the UX of your project.</p>
<p>This article is also available as a video tutorial as part of the <a target="_blank" href="https://www.youtube.com/playlist?list=PLIJrr73KDmRyQVT__uFZvaVfWPdfyMFHC">15 Days of React Design Patterns</a> <a target="_blank" href="https://www.youtube.com/playlist?list=PLIJrr73KDmRyQVT__uFZvaVfWPdfyMFHC">initiative</a>. Please check it out.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/x03yX-yNxas" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-what-is-optimistic-ui">What is Optimistic UI</a>?</p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-does-it-work-under-the-hood">How Does it Work Under the Hood?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-an-optimistic-like-button">How to Build an Optimistic Like Button</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-pitfalls-and-anti-patterns">The Pitfalls and Anti-Patterns</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-15-days-of-react-design-patterns">15 Days of React Design Patterns</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-before-we-end">Before We End...</a></p>
</li>
</ol>
<h2 id="heading-what-is-optimistic-ui">What is Optimistic UI?</h2>
<p><code>Optimistic UI</code> (also known as optimistic updates) is a pattern that helps you update the UI immediately, assuming the server operation will succeed, and if it later fails, you roll back the UI to the correct state.</p>
<p>Instead of waiting for the round-trip of the client request, database write, server response, and then the UI render, the UI just updates instantly. This dramatically increases what’s called the <code>perceived speed</code>. The user of the application perceives the UI update as instant – but the actual operation may take place in the background.</p>
<h3 id="heading-without-an-optimistic-update">Without an Optimistic Update:</h3>
<p>If you’re not using the optimistic pattern, it’s just a traditional client-server mechanism, where:</p>
<ul>
<li><p>At the client side, a user interacts with a UI element.</p>
</li>
<li><p>An <a target="_blank" href="https://www.youtube.com/watch?v=WQdCffdPPKI">async call</a> (request) is made to the server.</p>
</li>
<li><p>The server processes the request and may make DB updates.</p>
</li>
<li><p>On a successful case, the server sends back the response to the client.</p>
</li>
<li><p>The client updates the relevant UI.</p>
</li>
<li><p>In an error case, the server sends back the error response to the client.</p>
</li>
<li><p>The client informs the user about the error.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765334108586/aabd3f16-b175-4b1d-ae33-94f33e1b894a.png" alt="Without an Optimistic Update" class="image--center mx-auto" width="1240" height="704" loading="lazy"></p>
<p>In this case, the user has to wait for the success/failure of the request to perceive any change after their interaction. This wait is neither uniform nor optimal. It may vary based on the network speed, network latency, and deployment strategies of the application.</p>
<h3 id="heading-with-an-optimistic-update">With an Optimistic Update:</h3>
<p>When you’re using an optimistic update, here’s how things go:</p>
<ul>
<li><p>At the client side, a user interacts with a UI element.</p>
</li>
<li><p>The UI gets updated instantly, and the user perceives the feedback immediately.</p>
</li>
<li><p>In parallel, in the background, the client initiates the server call.</p>
</li>
<li><p>The server processes the request and may make DB updates.</p>
</li>
<li><p>On a successful case, the server doesn’t do anything else, as the UI has been updated already, assuming this call will succeed.</p>
</li>
<li><p>In an error case, the server sends back the error response to the client.</p>
</li>
<li><p>The client rolls back the eager, optimistic UI update it made.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765334174203/e8bef9ba-28b6-45e0-8f22-0fc1468e3219.png" alt="With an Optimistic Update" class="image--center mx-auto" width="1189" height="892" loading="lazy"></p>
<p>In this case, the user doesn’t wait for the server round-trip to complete before the UI is updated. It’s much faster, assuming that, in most cases, the parallel server call will succeed.</p>
<p>With this comparison, we can now understand why Optimistic Updates matter in modern UI.</p>
<ul>
<li><p>It improves perceived speed</p>
</li>
<li><p>It keeps users engaged</p>
</li>
<li><p>It eliminates the awkward feelings like “Did my click work?”</p>
</li>
</ul>
<p>And so on. Optimistic updates are critical for real-time feeling features like chat messages, likes, comments, cart updates, poll votes, collaborative editing, and more. Even AI-driven apps that take time to respond benefit from optimistic placeholders like “Thinking…”, “Sending…” and so on.</p>
<h2 id="heading-how-does-it-work-under-the-hood">How Does it Work Under the Hood?</h2>
<p>Under the hood, there are actually two states:</p>
<ol>
<li><p>The Actual State: This is the actual source of truth. This data should be in sync with the server.</p>
</li>
<li><p>The Optimistic State: This is temporary and instantly shown to the user.</p>
</li>
</ol>
<p>When the server request succeeds, do nothing. Your optimistic state is now correct. If the server request fails, perform a rollback, and return UI the actual state.</p>
<p>React 19 introduced a built-in hook to help with this pattern called <code>useOptimistic()</code> . In the next section, we will take a deep dive into it with code and working internals.</p>
<h3 id="heading-the-useoptimistic-hook-in-react-19">The <code>useOptimistic()</code> Hook in React 19</h3>
<p><code>useOptimistic()</code> is a React hook introduced in React 19 to help with optimistic updates. The syntax and usage of the hook go like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [optimisticState, addOptimistic] = useOptimistic(state, updateFn);
</code></pre>
<p>When an async action is underway, the <code>useOptimistic()</code> hook allows you to show different states.</p>
<p>It accepts:</p>
<ol>
<li><p><strong>currentState</strong>: your real source of truth (useState, Redux, server state, and so on)</p>
</li>
<li><p><strong>updateFn</strong>: a pure function that says how to compute the optimistic value</p>
</li>
</ol>
<p>It returns:</p>
<ol>
<li><p><strong>optimisticState</strong>: the temporary UI state</p>
</li>
<li><p><strong>addOptimisticUpdate(input)</strong>: function you call to apply immediate updates</p>
</li>
</ol>
<p>Take a look at the picture below. It shows the relationship between the current state and the optimistic state clearly:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765434835916/249e71eb-bba6-4b98-951a-feb397dc36e2.png" alt="Anatomy" class="image--center mx-auto" width="1744" height="781" loading="lazy"></p>
<p>Here’s what’s going on there:</p>
<ol>
<li><p>We pass the current state and an updater function to the <code>useOptimistic</code> hook.</p>
</li>
<li><p>The updater function takes the current state and a user input to compute and return the next optimistic state.</p>
</li>
<li><p>The input to the updater function is supplied using the <code>addOptimistic(input)</code> function.</p>
</li>
<li><p>Finally, the optimistic state value is used in the component.</p>
</li>
</ol>
<p>Let’s now build something exciting using this hook to understand its internals better.</p>
<h2 id="heading-how-to-build-an-optimistic-like-button">How to Build an Optimistic Like Button</h2>
<p>We will be building the Like button functionality optimistically. The flow will be like this:</p>
<ul>
<li><p>The user clicks on the Like button.</p>
</li>
<li><p>We update the Like button’s state immediately and optimistically.</p>
</li>
<li><p>In parallel, we send the server call to persist the value into the DB (we will simulate it)</p>
</li>
<li><p>Then we handle any error scenarios.</p>
</li>
</ul>
<p>First, let’s simulate a network call to the server using JavaScript’s Promise object and the <code>setTimeout()</code> web API:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// simulate a network call to the Server</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendLikeToServer</span>(<span class="hljs-params">postId</span>) </span>{
    <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">r</span>) =&gt;</span> <span class="hljs-built_in">setTimeout</span>(r, <span class="hljs-number">700</span>));

    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Math</span>.random() &lt; <span class="hljs-number">0.2</span>) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Network failed"</span>);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Sent a like for the post id <span class="hljs-subst">${postId}</span>`</span>);
    <span class="hljs-keyword">return</span> { <span class="hljs-attr">success</span>: <span class="hljs-literal">true</span> };
}
</code></pre>
<p>The <code>sendLikeToServer</code> function takes a post ID as a parameter and simulates a fake network call using a Promise and a delay of 700 ms. It pretends to submit a request to the server to persist a post’s likes value.</p>
<p>To make it a bit more realistic, we have created a random error. The function will throw an error randomly so that we can understand the rollback scenario as well.</p>
<p>Next, we will create the real source of truth, the actual state for the Like count:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [likes, setLikes] = useState(initialLikes);
</code></pre>
<p>Then, create the optimistic state value with the <code>useOptimistic()</code> hook:</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> [optimisticLikes, addOptimisticLike] = useOptimistic(
        likes, <span class="hljs-function">(<span class="hljs-params">currentLikes, delta</span>) =&gt;</span> currentLikes + delta);
</code></pre>
<p>Let’s understand this declaration well:</p>
<ul>
<li><p>We have passed the actual state value (likes) and the updater function to the <code>useOptimistic()</code> hook.</p>
</li>
<li><p>Take a look at the updater function, <code>(currentLikes, delta) =&gt; currentLikes + delta</code>. It’s an arrow function that gets the current like value and a delta. It returns the sum of the current like value and the delta. The return value logic is your own business logic. For incrementing the like count, it makes sense to increase the current like value by a delta value (of 1).</p>
</li>
<li><p>Now, the question is, how do we get this delta value? Who passes it? That’s where the return values of <code>useOptimistic()</code> come in handy. The <code>addOptimisticLike</code> is a function through which we can pass that delta value. How? Let’s take a look.</p>
</li>
</ul>
<p>When someone clicks on the Like button, we need to handle the click event and increase the like count value. So here is a <code>handleLike()</code> function which does that:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> handleLike = <span class="hljs-keyword">async</span> () =&gt; {
        addOptimisticLike(<span class="hljs-number">1</span>);
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">await</span> sendLikeToServer(postId);
            setLikes(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> prev + <span class="hljs-number">1</span>);
        } <span class="hljs-keyword">catch</span> (err) {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Like failed:"</span>, err);
            setLikes(<span class="hljs-function">(<span class="hljs-params">s</span>) =&gt;</span> s); 
        }
};
</code></pre>
<p>A lot is happening here:</p>
<ul>
<li><p>We call the <code>addOptimisticLike()</code> function with a delta value of 1. This call will ensure that the updater function <code>(currentLikes, delta) =&gt; currentLikes + delta</code> of the <code>useOptimistic()</code> will be called. The return value will be set to the optimistic state, that is, <code>optimisticLikes</code>.</p>
</li>
<li><p>This optimistic state value we use in the JSX. So we can see the increased like count immediately.</p>
</li>
<li><p>Then we make the fake server call, and also update the actual state, provided the server call was successful.</p>
</li>
<li><p>In case of an error, the control goes into the catch-block, where we roll back the likes value to the previous one. This will also sync the optimistic state’s value with a rollback.</p>
</li>
</ul>
<p>Here is the complete code of the <code>LikeButton</code> component:</p>
<pre><code class="lang-javascript">
<span class="hljs-keyword">import</span> { startTransition, useOptimistic, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-comment">// simulate a network call to the Server</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendLikeToServer</span>(<span class="hljs-params">postId</span>) </span>{
    <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">r</span>) =&gt;</span> <span class="hljs-built_in">setTimeout</span>(r, <span class="hljs-number">700</span>));

    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Math</span>.random() &lt; <span class="hljs-number">0.2</span>) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Network failed"</span>);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Sent a like for the post id <span class="hljs-subst">${postId}</span>`</span>);
    <span class="hljs-keyword">return</span> { <span class="hljs-attr">success</span>: <span class="hljs-literal">true</span> };
}

<span class="hljs-comment">// The Like Button Component</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">LikeButton</span>(<span class="hljs-params">{ postId, initialLikes = <span class="hljs-number">0</span> }</span>) </span>{
    <span class="hljs-comment">// the "real" source of truth for likes (committed)</span>
    <span class="hljs-keyword">const</span> [likes, setLikes] = useState(initialLikes);
    <span class="hljs-comment">// optimistic state and updater function</span>
    <span class="hljs-keyword">const</span> [optimisticLikes, addOptimisticLike] = useOptimistic(
        likes,
        <span class="hljs-function">(<span class="hljs-params">currentLikes, delta</span>) =&gt;</span> currentLikes + delta
    );

    <span class="hljs-keyword">const</span> handleLike = <span class="hljs-keyword">async</span> () =&gt; {
        <span class="hljs-comment">// 1) Apply optimistic change *immediately*</span>
        addOptimisticLike(<span class="hljs-number">1</span>);

        <span class="hljs-comment">// 2) Start server call in low priority to avoid blocking UI</span>

        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">await</span> sendLikeToServer(postId);
            <span class="hljs-comment">// On success, commit the real state update:</span>
            <span class="hljs-comment">// IMPORTANT: update the real state so optimistic snapshot eventually matches</span>
            setLikes(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> prev + <span class="hljs-number">1</span>);
        } <span class="hljs-keyword">catch</span> (err) {
            <span class="hljs-comment">// On error, rollback the real state (or trigger a refetch)</span>
            <span class="hljs-comment">// Because we never incremented likes (real), just leave likes unchanged</span>
            <span class="hljs-comment">// But we should show an error to user:</span>
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Like failed:"</span>, err);
            <span class="hljs-comment">// Optionally: show toast or set an error state</span>
            <span class="hljs-comment">// And — to force the optimistic view to refresh and reflect real state,</span>
            <span class="hljs-comment">// call setLikes to current value</span>
            setLikes(<span class="hljs-function">(<span class="hljs-params">s</span>) =&gt;</span> s); <span class="hljs-comment">// no-op but will cause optimistic to reflect the</span>
                                <span class="hljs-comment">// committed value Or you can trigger a re-fetch of the </span>
                                <span class="hljs-comment">// post state</span>
        }
    };

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleLike}</span>&gt;</span>❤️ {optimisticLikes}<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> startTransition(async () =&gt; handleLike())}&gt;
                ❤️ {optimisticLikes}
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
}
</code></pre>
<p>Have you noticed that we have wrapped the <code>handleLike()</code> call with the <code>startTransition</code>?</p>
<p>Without this, React gives us a warning:</p>
<blockquote>
<p>“An optimistic state update occurred outside a transition or action.”</p>
</blockquote>
<p>This is because optimistic updates are <strong>low-priority visual updates</strong>, not critical ones.</p>
<p>Using <code>startTransition()</code> ensures that:</p>
<ul>
<li><p>React doesn’t block rendering</p>
</li>
<li><p>We do not get the warning</p>
</li>
<li><p>We get a smooth, optimistic experience</p>
</li>
</ul>
<p>The transitions are part of React’s concurrency model that helps us improve the performance of React applications. If you are interested in learning various performance optimisation techniques, <a target="_blank" href="https://www.youtube.com/watch?v=G8Mk6lsSOcw">here is a two-part guide for you</a>.</p>
<h2 id="heading-the-pitfalls-and-anti-patterns">The Pitfalls and Anti-Patterns</h2>
<p>With any design pattern, we need to be aware of possible pitfalls, misuses, and anti-patterns. Here are a few things you should be aware of:</p>
<ul>
<li><p>Don’t assume that the server call will be successful. Network failure will happen, and you need to have a way to roll back. Rollback is the heart of optimistic UI. Omitting the rollback logic will cause adverse consequences.</p>
</li>
<li><p>Don’t try hiding the bad UX behind optimistic updates. The Optimistic UI is not a fix or replacement for poor designs.</p>
</li>
<li><p>Don’t perform any expensive work in optimistic updates. Keep the optimistic updater function lean, pure, and fast.</p>
</li>
</ul>
<h2 id="heading-15-days-of-react-design-patterns"><strong>15 Days of React Design Patterns</strong></h2>
<p>I have some great news for you: after my <em>40 days of the JavaScript</em> initiative, I have now started a brand new initiative called <a target="_blank" href="https://www.youtube.com/playlist?list=PLIJrr73KDmRyQVT__uFZvaVfWPdfyMFHC">15 Days of React Design Patterns</a>.</p>
<p>If you enjoyed learning from this article, I am sure you will love this series, featuring the 15+ most important React design patterns. Check it out and join for FREE:</p>
<p><a target="_blank" href="https://www.youtube.com/playlist?list=PLIJrr73KDmRyQVT__uFZvaVfWPdfyMFHC"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765439781697/751c2051-5dc2-4a88-bcc2-037f6ce0e91e.png" alt="https://www.youtube.com/playlist?list=PLIJrr73KDmRyQVT__uFZvaVfWPdfyMFHC" class="image--center mx-auto" width="1612" height="850" loading="lazy"></a></p>
<h2 id="heading-before-we-end"><strong>Before We End...</strong></h2>
<p>That’s all! I hope you found this article insightful. You can find all the source code used in this tutorial on the <a target="_blank" href="https://github.com/tapascript/15-days-of-react-design-patterns/tree/main/day-08">tapaScript GitHub</a>.</p>
<p><a target="_blank" href="https://github.com/tapascript/15-days-of-react-design-patterns/tree/main/day-03/compound-components-patterns">Let’s connect:</a></p>
<ul>
<li><p>Subscribe to my <a target="_blank" href="https://www.youtube.com/tapasadhikary?sub_confirmation=1">YouTube Channel</a>.</p>
</li>
<li><p>Grab the <a target="_blank" href="https://www.tapascript.io/books/react-hooks-cheatsheet">React Hooks Cheatsheet</a>.</p>
</li>
<li><p>Follow on <a target="_blank" href="https://www.linkedin.com/in/tapasadhikary/">LinkedIn</a> if you don't want to miss the daily dose of up-skilling tips.</p>
</li>
<li><p>Join my <a target="_blank" href="https://discord.gg/zHHXx4vc2H">Discord Server</a>, and let’s learn together.</p>
</li>
<li><p>Subscribe to my fortnightly newsletter, <a target="_blank" href="https://tapascript.substack.com/subscribe?utm_medium=fcc">The Commit Log</a>.</p>
</li>
</ul>
<p>See you soon with my next article. Until then, please take care of yourself and keep learning.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ System Design Patterns in Android Bluetooth [Full Handbook] ]]>
                </title>
                <description>
                    <![CDATA[ If you’ve ever opened the Android Bluetooth source code, you might know this feeling. You go in with the calm confidence of a developer who just wants to understand how things work. You open BluetoothAdapter.java and think, “Ah, this looks clean.” Th... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/system-design-patterns-in-android-bluetooth-full-handbook/</link>
                <guid isPermaLink="false">6915f7d8453f11c904fade0c</guid>
                
                    <category>
                        <![CDATA[ aosp ]]>
                    </category>
                
                    <category>
                        <![CDATA[ bluetooth ]]>
                    </category>
                
                    <category>
                        <![CDATA[ System Design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ design patterns ]]>
                    </category>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Nikheel Vishwas Savant ]]>
                </dc:creator>
                <pubDate>Thu, 13 Nov 2025 15:23:04 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1763047349934/78e1861c-62d3-44c8-adc3-971d6b63a7cc.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you’ve ever opened the Android Bluetooth source code, you might know this feeling.</p>
<p>You go in with the calm confidence of a developer who just wants to understand how things work. You open <code>BluetoothAdapter.java</code> and think, “Ah, this looks clean.” Then you click through a few methods. Suddenly, you’re in <code>AdapterService.java</code>, then <code>StateMachine.java</code>, and before you realize it, you’re staring at a JNI bridge leading straight into native C++ code that talks to daemons with names like <code>bluetoothd</code>.</p>
<p>Somewhere between the Binder calls, message queues, and “Unexpected state” logs, your curiosity quietly turns into existential dread.</p>
<p>That, my friend, is the Android Bluetooth experience.</p>
<p>But here’s the twist: it’s not chaos. It’s choreography. Every message, callback, and native call exists for a reason. Android Bluetooth has been built, rebuilt, and evolved over more than a decade to support everything from old-school car kits to cutting-edge LE Audio.</p>
<p>Underneath that ever-expanding complexity lies a remarkably disciplined foundation built on <strong>system design patterns</strong>. These patterns are the reason Bluetooth can still work across thousands of devices, dozens of chip vendors, and millions of random user interactions that happen every second.</p>
<p>What’s fascinating is how the Bluetooth stack mirrors Android’s entire design philosophy: isolate complexity, define clear roles, and let components communicate through predictable contracts.</p>
<p>The app layer talks to managers. The managers talk to services. The services talk to native daemons. And the daemons finally talk to the hardware. Each layer speaks its own language but follows a shared rhythm –like musicians who have never met but somehow stay in tune.</p>
<p><img src="https://www.androidauthority.com/wp-content/uploads/2018/03/Bluetooth-Icon-Settings-Menu.jpg" alt="What is Bluetooth and how does it work? - Android Authority" width="600" height="400" loading="lazy"></p>
<p>Without these patterns, the system would collapse under its own ambition. Imagine writing logic for pairing, bonding, discovery, connection, streaming, and low-energy data transfer without structure. Every change would be a minefield.</p>
<p>Design patterns bring sanity to this chaos.</p>
<ul>
<li><p>The <strong>Manager-Service split</strong> ensures clear boundaries.</p>
</li>
<li><p>The <strong>State Machine</strong> keeps connection lifecycles predictable.</p>
</li>
<li><p>The <strong>Handler-Looper mechanism</strong> turns concurrency into an orderly queue.</p>
</li>
<li><p>The <strong>Facade</strong> hides native messiness behind friendly APIs.</p>
</li>
<li><p>And the <strong>Observer</strong> pattern lets everyone stay updated without tripping over each other.</p>
</li>
</ul>
<p>This article is about peeling back those layers and seeing the design ideas that quietly keep Android Bluetooth alive. We won’t just list patterns like a textbook. Instead, we’ll explore how each one appears in real AOSP code, why it exists, and how you can apply the same ideas to your own projects.</p>
<p>If you’ve ever wondered how something as temperamental as Bluetooth manages to stay mostly reliable, this is your backstage pass.</p>
<p>So grab your debugger, open a terminal window, and get ready to look at Bluetooth not as a mysterious black box, but as one of Android’s most elegant examples of long-term system design done right.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-the-manager-service-pattern-divide-and-delegate">The Manager–Service Pattern: Divide and Delegate</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-facade-pattern-making-complexity-look-simple">The Facade Pattern: Making Complexity Look Simple</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-state-machine-pattern-keeping-bluetooth-sane">The State Machine Pattern: Keeping Bluetooth Sane</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-handler-looper-pattern-message-driven-concurrency">The Handler–Looper Pattern: Message-Driven Concurrency</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-observer-pattern-when-bluetooth-talks-back">The Observer Pattern: When Bluetooth Talks Back</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-builder-pattern-making-gatt-bearable">The Builder Pattern: Making GATT Bearable</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-strategy-pattern-adapting-to-different-devices">The Strategy Pattern: Adapting to Different Devices</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-template-method-pattern-common-flows-custom-details">The Template Method Pattern: Common Flows, Custom Details</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-service-locator-pattern-finding-the-right-profile-at-runtime">The Service Locator Pattern: Finding the Right Profile at Runtime</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-layered-architecture-pattern-from-app-to-radio-without-losing-the-plot">The Layered Architecture Pattern: From App to Radio Without Losing the Plot</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-putting-it-all-together-designing-bluetooth-style-systems">Putting It All Together: Designing Bluetooth-Style Systems</a></p>
</li>
</ol>
<h2 id="heading-the-managerservice-pattern-divide-and-delegate">The Manager–Service Pattern: Divide and Delegate</h2>
<p>When you start exploring Android’s Bluetooth codebase, one of the first things you’ll notice is how often you come across the words “Manager” and “Service.” There is <code>BluetoothManagerService</code>, <code>AdapterService</code>, <code>GattService</code>, <code>A2dpService</code>, and many more.</p>
<p>At first, it seems repetitive and unnecessarily complicated. Why do we need so many layers just to connect to a pair of earbuds? Wouldn’t one class that says “connect” be enough? The short answer is no. The longer answer involves one of Android’s most reliable architectural habits: the separation of responsibility.</p>
<p>Think of a restaurant. The customers talk to the waiter. The waiter talks to the kitchen. The kitchen talks to suppliers. Everyone has a job. The waiter doesn’t need to know how to cook, and the chef doesn’t need to explain menu prices to customers. That separation is what keeps the whole operation smooth and manageable.</p>
<p>Android’s Bluetooth system works in exactly the same way. The <strong>Manager</strong> is like the waiter, the public face that interacts with apps, while the <strong>Service</strong> is like the kitchen, where the actual work happens out of sight.</p>
<p>When you write an app that uses Bluetooth, you might call something like <code>BluetoothAdapter.enable()</code> or <code>BluetoothDevice.connectGatt()</code>. These methods live inside Manager classes in the Android framework. They are deliberately simple, because their only job is to talk to the Bluetooth Service behind the scenes. That Service runs in another process entirely, one that has the necessary system permissions and the ability to interact with the native Bluetooth stack and hardware.</p>
<p>A small example from the Android source code shows this relationship very clearly:</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BluetoothManagerService</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">IBluetoothManager</span>.<span class="hljs-title">Stub</span> </span>{
    <span class="hljs-keyword">private</span> AdapterService mAdapterService;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">enable</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">if</span> (mAdapterService != <span class="hljs-keyword">null</span>) {
            <span class="hljs-keyword">return</span> mAdapterService.enable();
        }
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
    }
}
</code></pre>
<p>At first glance, this looks trivial, but it demonstrates one of the most important ideas in the system. The <code>BluetoothManagerService</code> does not handle radio operations itself. Instead, it delegates to another internal class called <code>AdapterService</code>, which communicates with lower layers. That service will eventually pass instructions down to native C++ code, which then communicates with the Bluetooth controller chip through the Host Controller Interface.</p>
<p>This relay-style design has several advantages. The first is reliability. If the lower-level service crashes, the Manager layer can detect it and restart it, keeping the system stable. Because the Manager and the Service live in separate processes, your app will not crash when the service does. You might see Bluetooth temporarily toggle off and on again, but that recovery is intentional and automatic.</p>
<p>The second advantage is security. Every Bluetooth action goes through permission checks in the Manager layer before it reaches the Service. If an app without proper privileges tries to perform a restricted operation, the Manager stops it immediately. This prevents unsafe or malicious behavior and ensures that only trusted system components can access the hardware.</p>
<p>The third is flexibility. The Service layer can evolve without affecting the public API. That means Google and device manufacturers can modify or replace internal Bluetooth logic say, to support a new chipset or feature, without breaking existing apps. The Manager acts as a contract that remains stable even if the internal wiring changes.</p>
<p>If you trace what happens when you tap the Bluetooth toggle on your phone, you can see this pattern in action. Your tap calls <code>BluetoothAdapter.enable()</code> in the app layer. That call travels to <code>BluetoothManagerService</code> in the system server process. The manager checks permissions, then calls <code>AdapterService.enable()</code>. Inside the service, a JNI bridge triggers a native C++ function called <code>enableNative()</code>, which finally sends a command to the hardware abstraction layer. From there, it reaches the Bluetooth chip itself. Each layer knows its exact role.</p>
<p>This organization also makes debugging easier. If something goes wrong, you can tell whether it’s the Manager that didn’t send a message, the Service that failed to respond, or the native stack that stopped working. Each part logs its own activity in logcat, so you can follow the chain of events without guessing where the problem began.</p>
<p>At its core, the Manager–Service pattern is Android’s way of keeping large systems under control. It divides authority, enforces security, and lets the entire Bluetooth subsystem recover gracefully from errors. It may look complicated at first, but it is this design that makes Bluetooth remarkably resilient. Every time your phone connects to your car or your earbuds, it happens through this carefully choreographed handoff between the Manager and the Service. It’s a quiet partnership that keeps billions of connections running smoothly every single day.</p>
<h2 id="heading-the-facade-pattern-making-complexity-look-simple">The Facade Pattern: Making Complexity Look Simple</h2>
<p>If the Manager–Service pattern is about dividing responsibility, the Facade pattern is about hiding chaos behind elegance. In many ways, this is the reason most Android developers can use Bluetooth without needing to understand what happens inside the stack.</p>
<p>The Facade pattern provides a friendly public face that masks a labyrinth of underlying operations, creating an illusion of simplicity while managing a tremendous amount of behind-the-scenes work.</p>
<p>To understand this, think about the front desk of a large hotel. When you check in, you talk to one receptionist. That person gives you your key, answers questions, and takes requests. You never meet the maintenance crew fixing the air conditioning or the kitchen staff preparing food or the team handling room cleaning schedules. Yet all those systems quietly operate through that one friendly front desk.</p>
<p>That front desk is the Facade. It provides a simple interface to a complex system, ensuring guests never have to deal with the hotel’s internal machinery.</p>
<p>Android’s Bluetooth framework works in the same way. Developers interact with high-level classes such as <code>BluetoothAdapter</code>, <code>BluetoothDevice</code>, and <code>BluetoothGatt</code>. These classes are the front desks of the Bluetooth system. They provide clean, easy-to-use APIs like <code>enable()</code>, <code>getBondedDevices()</code>, and <code>connectGatt()</code>.</p>
<p>When a developer calls one of these methods, it looks straightforward. But beneath the surface, that call passes through multiple layers of services, IPC mechanisms, and native components before reaching the Bluetooth controller hardware.</p>
<p>Here is a simplified example to illustrate how this works in practice:</p>
<pre><code class="lang-java">BluetoothGatt gatt = device.connectGatt(context, <span class="hljs-keyword">false</span>, callback);
</code></pre>
<p>This single line looks simple. But in reality, it triggers an entire orchestra of operations. The call goes through the <code>BluetoothDevice</code> class, which forwards the request to <code>BluetoothGatt</code>. The <code>BluetoothGatt</code> instance then communicates with the system’s Bluetooth service through Binder IPC. That service eventually invokes native code that sets up an L2CAP channel, negotiates attributes, configures encryption, and starts the Generic Attribute Profile (GATT) procedure. None of that complexity is visible to the developer who wrote the original line.</p>
<p>This is what makes the Facade pattern so powerful. It provides abstraction without removing capability. The Android team knows that very few app developers want to worry about connection intervals, PHY configurations, or attribute protocol responses. They just want to connect to a device and get data. By exposing a Facade, Android lets developers stay productive while the internal layers handle the technical details.</p>
<p>If you look at the Android source tree, you can see this pattern clearly in how Bluetooth is organized. The classes in the <code>android.bluetooth</code> package are intentionally designed to be simple and self-contained. They never reveal how the system service works.</p>
<p>For example, <code>BluetoothAdapter</code> doesn’t know how to send HCI commands, and <code>BluetoothGatt</code> doesn’t know how to open a socket. Instead, they act as representatives, forwarding user requests to the Bluetooth Manager or the corresponding Service, which then interacts with the native stack.</p>
<p>This pattern is what makes the Bluetooth API approachable to beginners. Imagine if Android exposed every detail of the underlying protocols to developers. You would have to manually construct attribute requests, negotiate connection intervals, and handle packet fragmentation. The result would be technically accurate but completely unusable for most app developers. The Facade prevents that by serving as a translation layer between human expectations and machine complexity.</p>
<p>There is also a deeper design reason behind this approach. A Facade protects stability. Because developers only see the outermost layer, Android engineers can modify the internals without breaking existing apps. This allows the system to evolve freely, improving performance and adding new features while keeping the public API consistent.</p>
<p>The Bluetooth internals have changed countless times since the early days of Android, but <code>BluetoothAdapter.startDiscovery()</code> still works the same way it did a decade ago. That consistency is a direct benefit of the Facade pattern.</p>
<p>In a sense, the Facade pattern is about empathy. It respects the developer’s time by not forcing them to learn every Bluetooth nuance. It makes working with a complicated protocol feel human. Whether you are scanning for nearby devices, connecting to a smartwatch, or transferring data, you only need to call a few readable methods and handle a handful of callbacks. Behind those calls, a world of threads, sockets, and packet exchanges whirs silently to life, all hidden behind a calm, minimal interface.</p>
<p>So the next time you call <code>BluetoothAdapter.enable()</code> and your phone’s Bluetooth magically comes to life, remember that you are not flipping a simple switch. You are sending a message through a carefully designed Facade that talks to multiple services, native layers, and hardware interfaces. It is like pressing a single button on a spaceship console while a thousand mechanical parts start moving in perfect synchronization. You don’t see the complexity, and that is precisely the point.</p>
<h2 id="heading-the-state-machine-pattern-keeping-bluetooth-sane">The State Machine Pattern: Keeping Bluetooth Sane</h2>
<p>If you have ever debugged Bluetooth connections, you have probably experienced moments of pure confusion. One minute the device says “Connecting,” then suddenly it jumps to “Connected,” then “Disconnected,” then “Connecting” again, and before you know it, you have no idea what the current state actually is.</p>
<p>Bluetooth is, by nature, an unpredictable environment. Devices move in and out of range, radio interference causes delays, and remote devices can behave differently depending on their chipsets. To make sense of all this unpredictability, Android relies on one of the most battle-tested concepts in computer science: the <strong>State Machine</strong> pattern.</p>
<p>A state machine is like a rulebook that defines how a system behaves depending on its current situation. Instead of reacting randomly to every event, the system maintains a clear notion of “state.”</p>
<p>For Bluetooth, these states might include <em>Disconnected</em>, <em>Connecting</em>, <em>Connected</em>, or <em>Disconnecting</em>. Each state knows exactly what actions are allowed and what transitions are possible.</p>
<p>For example, you can only go from <em>Disconnected</em> to <em>Connecting</em> when a connection attempt starts, and you can only go from <em>Connecting</em> to <em>Connected</em> if the handshake succeeds. If something happens that does not make sense for the current state, the system simply ignores it. This structure prevents chaos.</p>
<p>In Android’s Bluetooth implementation, almost every major profile uses a state machine. You can find them in classes like <code>A2dpStateMachine.java</code> and <code>HeadsetStateMachine.java</code>. Each one extends a generic <code>StateMachine</code> framework that Android provides. The structure is surprisingly elegant. You define individual classes for each state, implement their behaviors, and let the system handle the transitions. Conceptually, it looks like this:</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">A2dpStateMachine</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StateMachine</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> State mDisconnected = <span class="hljs-keyword">new</span> Disconnected();
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> State mConnecting = <span class="hljs-keyword">new</span> Connecting();
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> State mConnected = <span class="hljs-keyword">new</span> Connected();

    A2dpStateMachine() {
        addState(mDisconnected);
        addState(mConnecting);
        addState(mConnected);
        setInitialState(mDisconnected);
    }
}
</code></pre>
<p>Although the code may look technical, the idea is simple. Each “State” represents a specific mode of operation, and each one defines how to react to incoming events.</p>
<p>The system starts in <em>Disconnected</em>. When a “connect” command arrives, it moves to <em>Connecting</em>. When the connection completes, it moves to <em>Connected</em>. If the user turns off Bluetooth or the remote device disappears, it transitions back to <em>Disconnected</em>. Every action follows a logical, well-defined path.</p>
<p>This pattern is what keeps Bluetooth stable despite the messy nature of wireless communication. Without it, you would constantly end up with half-open connections, dangling callbacks, and undefined behaviors. Imagine a phone that still thinks it’s connected to your headphones long after you have turned them off. The state machine eliminates that by keeping a single source of truth for connection status.</p>
<p>Beyond correctness, the state machine pattern also improves readability and maintenance. Each state is self-contained, so developers can easily locate the logic that handles a particular situation. If you need to change how Bluetooth behaves when connecting, you only modify the <em>Connecting</em> class, not the entire codebase. This modularity makes the Bluetooth stack easier to evolve as new profiles and features appear.</p>
<p>There is also a subtle psychological benefit to using state machines. When debugging, engineers can trace log messages that indicate transitions, such as “A2dpStateMachine: Transitioning from CONNECTING to CONNECTED.” These logs act like a map of the system’s thought process. Instead of guessing what happened, you can follow a clear narrative of cause and effect. That is invaluable in a system as complex as Bluetooth, where timing issues can hide bugs that are otherwise impossible to reproduce.</p>
<p>State machines also ensure graceful recovery. Suppose a connection fails halfway through. Without structured states, the system might leave resources allocated or callbacks registered. But with a state machine, the <em>Connecting</em> state knows how to clean up before returning to <em>Disconnected</em>. This reduces leaks, power drain, and inconsistent user experiences.</p>
<p>Even at higher levels of Android, you can see the influence of this pattern. For example, when you toggle Bluetooth on or off, the adapter itself transitions through a sequence of states internally: <em>Turning On</em>, <em>On</em>, <em>Turning Off</em>, <em>Off</em>. This ensures that all dependent services, such as GATT and A2DP, are brought up or down in the right order. The pattern guarantees that nothing jumps ahead or lags behind during these transitions.</p>
<p>In everyday terms, the state machine pattern is like traffic lights for Bluetooth. It prevents every component from driving through the intersection at the same time. Each action has a green, yellow, or red light depending on the current situation. This orderliness is what keeps Bluetooth from descending into radio chaos every time multiple devices try to connect or disconnect at once.</p>
<p>So, the next time your phone automatically reconnects to your headphones after a short disconnection, remember that it is not luck. It is a carefully choreographed set of state transitions keeping track of where everything stands. Behind every smooth Bluetooth experience lies a quiet but dependable state machine making sure each event happens exactly when it should and never when it shouldn’t.</p>
<h2 id="heading-the-handlerlooper-pattern-message-driven-concurrency">The Handler–Looper Pattern: Message-Driven Concurrency</h2>
<p>If Bluetooth had a personality, it would be that friend who cannot sit still. It’s constantly juggling tasks: scanning for devices, maintaining connections, handling GATT operations, streaming audio, and sending data to the controller, all at once. Underneath that hustle is one of Android’s most reliable design foundations: the <strong>Handler–Looper</strong> pattern. This pattern is what keeps Bluetooth responsive, synchronized, and stable even when a dozen things happen at the same time.</p>
<p>To understand why it exists, imagine running a busy coffee shop with only one employee who tries to handle every customer request immediately. One person takes an order, makes the drink, cleans the counter, and washes the cups all in real time. Within minutes, chaos erupts. Customers start yelling, the counter gets sticky, and no one knows who’s being served.</p>
<p>Now, imagine a more organized system: every order goes into a queue, and the barista processes them one by one. That’s essentially how the Handler–Looper system works.</p>
<p>In Android, almost everything that involves background work happens through <strong>message queues</strong>. The <strong>Looper</strong> represents a thread that waits for messages, and the <strong>Handler</strong> is the entity that posts those messages into the queue.</p>
<p>Instead of letting different threads modify shared Bluetooth state directly, which could easily lead to race conditions, Android forces all Bluetooth operations to happen on specific threads managed by loopers. Messages arrive, get handled in order, and the system never loses track of what happened first or last.</p>
<p>Inside the Bluetooth system, this pattern appears everywhere. Each service, such as <code>AdapterService</code>, <code>GattService</code>, or <code>A2dpService</code>, has its own Handler running on a dedicated thread. When a Bluetooth event occurs, like “Device Connected” or “Start Discovery,” the event is wrapped in a <code>Message</code> object and sent to the appropriate Handler. That Handler then decides what to do next. The pattern turns what could have been a tangle of multithreaded chaos into a clear, sequential pipeline.</p>
<p>Here’s a simplified example inspired by Android’s real Bluetooth code:</p>
<pre><code class="lang-java"><span class="hljs-keyword">private</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AdapterServiceHandler</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Handler</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">handleMessage</span><span class="hljs-params">(Message msg)</span> </span>{
        <span class="hljs-keyword">switch</span> (msg.what) {
            <span class="hljs-keyword">case</span> MSG_START_DISCOVERY:
                startDiscoveryNative();
                <span class="hljs-keyword">break</span>;
            <span class="hljs-keyword">case</span> MSG_STOP_DISCOVERY:
                stopDiscoveryNative();
                <span class="hljs-keyword">break</span>;
        }
    }
}
</code></pre>
<p>This code might look plain, but it’s quietly doing something brilliant. Instead of running <code>startDiscoveryNative()</code> directly, the system posts a message saying, “Hey, when you get a chance, start discovery.” The Looper thread eventually picks up that message and executes it in the correct order. No two threads ever collide, and the main thread stays free to handle user interactions.</p>
<p>The beauty of this approach lies in its predictability. Bluetooth events often happen in unpredictable sequences: a connection attempt might fail while a scan is still in progress, or a new device might appear while another is being paired. Without strict message ordering, these overlaps could lead to deadlocks or inconsistent states. By channeling every operation through a single message queue, Android ensures that Bluetooth behaves deterministically, no matter how chaotic the radio environment becomes.</p>
<p>It also helps with <strong>thread safety</strong>. Instead of sprinkling locks everywhere in the code, Android simply guarantees that all critical Bluetooth work happens on the same thread. This means developers can focus on logic instead of worrying about synchronization bugs. It’s one of those design choices that looks simple but saves thousands of hours of debugging across devices and vendors.</p>
<p>There’s another hidden benefit too: <strong>graceful recovery</strong>. If something goes wrong inside a message handler, say a native call fails or a timeout occurs, the system can isolate that failure to a single message. The rest of the queue continues processing normally. This containment prevents one bad operation from crashing the entire Bluetooth stack.</p>
<p>When you watch logcat during a Bluetooth session, you can often see the Handler–Looper pattern in action. You’ll find lines like “MSG_START_DISCOVERY received” followed by “Starting discovery” and “MSG_STOP_DISCOVERY received.” Those logs are more than just printouts – they are breadcrumbs showing the system’s thought process as it moves through the queue.</p>
<p>In simpler terms, the Handler–Looper pattern is how Android Bluetooth keeps its cool. It takes a storm of asynchronous events, pairing requests, advertisements, data packets, disconnections, and lines them up in a single, calm queue. It ensures that everything happens in order, every time.</p>
<p>So, the next time your phone seamlessly switches from one Bluetooth speaker to another while still streaming music and scanning for your watch in the background, remember what’s quietly at work beneath it all. There’s a dedicated thread looping patiently, reading messages, and keeping order in a world of wireless chaos. It’s the unsung hero of concurrency, one message at a time.</p>
<h2 id="heading-the-observer-pattern-when-bluetooth-talks-back">The Observer Pattern: When Bluetooth Talks Back</h2>
<p>Bluetooth is a chatterbox. It never works alone, and is always reacting to something. A device connects, another disconnects, a new advertisement appears, a bond is created, or a characteristic changes its value. The system needs to keep dozens of components informed about these changes in real time.</p>
<p>This is where the <strong>Observer pattern</strong> comes in. This pattern is all about communication, letting different parts of the system stay updated without constantly asking what’s going on.</p>
<p>The basic idea is simple. You have one source of truth that broadcasts updates, and you have multiple listeners that care about those updates. Whenever the source changes, it notifies everyone who subscribed. It’s like a news channel that sends breaking alerts to subscribers instead of waiting for each viewer to call in and ask, “Anything new today?”</p>
<p>In Android Bluetooth, this is how almost all notifications and callbacks are delivered. When your phone connects to a Bluetooth device, the Bluetooth system service sends out an event. The app doesn’t have to keep checking the connection status every second. Instead, it simply registers a listener that reacts whenever the connection state changes. That listener could be a <code>BroadcastReceiver</code> in the app or a callback interface provided by the framework.</p>
<p>For example, when a device connects, Android sends out a broadcast intent like this:</p>
<pre><code class="lang-java">sendBroadcast(<span class="hljs-keyword">new</span> Intent(BluetoothDevice.ACTION_ACL_CONNECTED));
</code></pre>
<p>Apps that have registered for this intent receive it automatically. They can then update their user interface, show a notification, or start another operation based on the new state. The same mechanism works for disconnections, bonding events, and discovery results. It’s an elegant way of keeping apps informed without them wasting energy by constantly polling the system.</p>
<p>At the GATT level, the Observer pattern takes a slightly different form. When you connect to a Bluetooth Low Energy device and subscribe to a characteristic, you provide a callback called <code>BluetoothGattCallback</code>. This callback has methods such as <code>onConnectionStateChange()</code> and <code>onCharacteristicChanged()</code>. Whenever the device sends new data, the system automatically invokes the appropriate callback on your behalf. You don’t need to ask for updates repeatedly – you simply react when they arrive.</p>
<p>The real beauty of this pattern is how decoupled it makes the system. The Bluetooth framework can notify multiple apps and services simultaneously without knowing anything about how they use the information. It just broadcasts an event and moves on. Each listener independently decides what to do with it.</p>
<p>This design is crucial for a multitasking operating system like Android, where Bluetooth events may be relevant to different components at the same time. For example, the system settings might need to update the connection icon, the media framework might need to route audio, and an app might need to sync data — all triggered by the same connection event.</p>
<p>The Observer pattern also helps with efficiency. Because updates are sent only when something changes, there is no unnecessary processing or battery drain from constant status checks. This design allows the Bluetooth stack to stay responsive while minimizing overhead, which is especially important for mobile devices that need to preserve both power and performance.</p>
<p>In practical terms, this pattern is what makes Bluetooth feel alive. When you open your Bluetooth settings and instantly see your device name appear or disappear, that’s the result of observers doing their job. They are always listening for broadcasts and updating the interface the moment something changes. Without this mechanism, your Bluetooth menu would lag or require manual refreshing just to stay current.</p>
<p>There is also a subtle reliability benefit. Observers can join or leave at any time without breaking the system. If one app crashes or unregisters its listener, others still receive updates normally. This flexibility ensures that the Bluetooth service remains stable even if individual apps behave unpredictably.</p>
<p>So, the next time your phone pops up a notification that your earbuds have connected or your smartwatch silently syncs in the background, remember that it is not magic. It’s the Observer pattern at work: a polite messaging system that lets Bluetooth quietly talk to everyone who is listening, all without raising its voice.</p>
<h2 id="heading-the-builder-pattern-making-gatt-bearable">The Builder Pattern: Making GATT Bearable</h2>
<p>If you have ever worked with Bluetooth Low Energy, you already know that the GATT layer can be a maze. The Generic Attribute Profile, or GATT, is how devices expose data to one another. It defines services, characteristics, and descriptors that describe everything from a heart rate monitor’s readings to a light bulb’s brightness. On paper, it’s beautifully organized. In practice, setting it up manually can feel like assembling furniture without instructions, using only an Allen key and pure faith.</p>
<p>When Android engineers designed the Bluetooth GATT APIs, they realized that developers would need a way to build these services and characteristics without losing their minds. That is where the <strong>Builder pattern</strong> comes in. This pattern is all about constructing complex objects step by step, instead of trying to do everything in one chaotic go.</p>
<p>Think of it like building a sandwich. You start with a base, then add layers: bread, sauce, lettuce, tomato, cheese, and so on. You can add or skip ingredients as needed, and by the end, you have a complete meal that makes sense.</p>
<p>The Builder pattern works the same way. It lets you create a GATT service one piece at a time, adding characteristics and descriptors in a readable, modular fashion.</p>
<p>In Android, a GATT service is represented by the <code>BluetoothGattService</code> class, and each piece of data it exposes is represented by a <code>BluetoothGattCharacteristic</code>. Instead of requiring you to manually wire all of these together in one long, confusing block, Android allows you to build them step by step, like this:</p>
<pre><code class="lang-java">BluetoothGattService service = <span class="hljs-keyword">new</span> BluetoothGattService(SERVICE_UUID,
        BluetoothGattService.SERVICE_TYPE_PRIMARY);

BluetoothGattCharacteristic characteristic =
        <span class="hljs-keyword">new</span> BluetoothGattCharacteristic(CHAR_UUID,
                BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_WRITE,
                BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE);

service.addCharacteristic(characteristic);
</code></pre>
<p>Even though this looks simple, it reflects a powerful design philosophy. Each method call adds a new layer of configuration without breaking readability. You can look at the code and instantly understand what kind of service you’re creating, what characteristics it contains, and what permissions each one has. There are no massive constructors, no messy parameter lists, and no confusion about what goes where.</p>
<p>This pattern does more than make code pretty. It also prevents errors. GATT structures are very sensitive to incorrect configurations, for example if a characteristic lacks the right permission or if a descriptor is missing. By breaking the setup into small, incremental steps, the Builder pattern helps developers validate each part as they go. It’s much easier to debug a missing characteristic when each one is clearly defined, rather than buried inside a giant, monolithic block of code.</p>
<p>The same idea applies internally within the Android Bluetooth stack. When the system builds its own GATT tables or processes client requests, it follows the same step-by-step assembly model. Each stage of the process adds more detail to the overall structure. The result is not only easier to read but also more robust in handling changes.</p>
<p>There is also a psychological benefit to this approach. Developers can focus on one small piece at a time instead of feeling overwhelmed by the entire setup. It feels like progress, and it reduces the cognitive load that often comes with working on protocols like GATT, where small mistakes can cause big headaches.</p>
<p>In a broader sense, the Builder pattern in Android Bluetooth is a lesson in humility. It acknowledges that complex systems are built incrementally, not in one heroic line of code. It invites you to slow down, define what you need clearly, and construct it carefully. Whether you are setting up a health monitor or designing a custom BLE sensor, the Builder pattern ensures that your code remains clear and maintainable as your project grows.</p>
<p>So the next time you define a Bluetooth service in your app and everything just works, take a moment to appreciate the quiet genius of the Builder pattern. It’s the reason you can build an entire wireless data model with a few readable lines instead of a spaghetti of function calls. It turns the intimidating world of GATT into something almost enjoyable, a reminder that even in low-level systems programming, design elegance still matters.</p>
<h2 id="heading-the-strategy-pattern-adapting-to-different-devices">The Strategy Pattern: Adapting to Different Devices</h2>
<p>Bluetooth, as anyone who has worked with it knows, is not one single, predictable standard in practice. It’s more like a family reunion where every cousin claims to follow the same rules but each one interprets them differently. One device might handle extended advertising perfectly, another insists on using legacy commands, and yet another behaves strangely when it comes to pairing.</p>
<p>In this unpredictable world, Android cannot rely on one fixed set of behaviors. It needs a system that can adapt depending on what kind of device or chipset it is dealing with. This is where the <strong>Strategy pattern</strong> quietly saves the day.</p>
<p>The Strategy pattern is all about flexibility. It allows a system to choose between multiple approaches at runtime depending on the situation. Instead of writing huge <code>if-else</code> blocks to handle every possible scenario, developers define a common interface that represents a behavior, and then create different implementations of that behavior. The system can then pick the right strategy dynamically.</p>
<p>Imagine you are a chef who must cook for guests with different dietary preferences. You don’t rewrite the entire recipe each time someone says they are vegan or gluten-free. Instead, you have multiple cooking strategies, one for each diet, and you simply pick the right one when the order comes in. Android does the same thing with Bluetooth.</p>
<p>Inside the Bluetooth stack, different devices and chipsets support different capabilities. Some controllers can handle multiple advertising sets, some cannot. Some prefer extended packet formats, while others only understand the older legacy commands. To manage this diversity without making the code unreadable, Android uses interchangeable strategies.</p>
<p>For example, when the system needs to start Bluetooth advertising, it doesn’t hard-code every possible hardware path. Instead, it defines an abstract interface, something like:</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">AdvertisingStrategy</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">startAdvertising</span><span class="hljs-params">()</span></span>;
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">stopAdvertising</span><span class="hljs-params">()</span></span>;
}
</code></pre>
<p>Then it provides specific implementations for each scenario, such as a <code>LegacyAdvertisingStrategy</code> and an <code>ExtendedAdvertisingStrategy</code>. Depending on the chipset capabilities, the system decides which strategy to use at runtime:</p>
<pre><code class="lang-java">AdvertisingStrategy strategy = controller.supportsExtendedAdvertising()
        ? <span class="hljs-keyword">new</span> ExtendedAdvertisingStrategy()
        : <span class="hljs-keyword">new</span> LegacyAdvertisingStrategy();
strategy.startAdvertising();
</code></pre>
<p>This design keeps the code clean and extensible. If a new Bluetooth version introduces a new advertising method, developers can simply implement another strategy class without touching the existing ones. The same approach appears in connection handling, power management, and even encryption policies.</p>
<p>The Strategy pattern also allows for graceful fallback. Suppose a modern device supports extended advertising but something goes wrong, maybe the controller firmware has a bug. Instead of crashing, the system can quietly switch back to the legacy strategy. Users never notice the change, and Bluetooth continues working.</p>
<p>Beyond hardware adaptability, this pattern also simplifies testing. Developers can easily substitute one strategy with another in unit tests to simulate different hardware configurations. It encourages modularity, which is crucial for a system that runs across hundreds of Android devices made by dozens of manufacturers.</p>
<p>You can also see the philosophical elegance in how this pattern aligns with Bluetooth itself. The Bluetooth protocol is inherently designed for negotiation. Devices exchange capabilities, choose compatible settings, and then proceed. Android’s software architecture mirrors that philosophy at the code level. By using strategies, it lets the system negotiate internally too, not between devices, but between code paths.</p>
<p>From a practical standpoint, the Strategy pattern gives Android the superpower of evolution. As new Bluetooth versions emerge with new features like LE Audio, Isochronous Channels, or Periodic Advertising, Android can keep up simply by introducing new strategy classes. There is no need to overhaul the entire system or rewrite large chunks of legacy logic.</p>
<p>So when your phone seamlessly connects to both a five-year-old Bluetooth speaker and a brand-new pair of earbuds using LE Audio, it’s not luck. It is design. Underneath the surface, Android is quietly picking the right strategy for each device, making the whole experience look effortless. It’s one of those cases where smart architecture turns what could have been a compatibility nightmare into a smooth, invisible handshake between hardware generations.</p>
<h2 id="heading-the-template-method-pattern-common-flows-custom-details">The Template Method Pattern: Common Flows, Custom Details</h2>
<p>In large systems like Android Bluetooth, not every part of the code can be entirely unique. Some operations follow the same general flow every time, but with small variations in the details. For example, connecting to a device, discovering services, or streaming audio all share similar high-level steps.</p>
<p>The pattern that allows Android to reuse these general flows while still letting each Bluetooth profile define its own personality is the <strong>Template Method</strong> pattern.</p>
<p>The essence of this pattern is simple: define the overall process once, but let subclasses decide how specific parts should behave. It’s like giving every chef in a restaurant the same recipe outline – prepare ingredients, cook, and plate – but letting each of them choose their own spices and techniques for flavor. The structure remains constant, but the details can vary.</p>
<p>Bluetooth needs this because different profiles, such as A2DP for audio or GATT for data exchange, often perform similar actions in slightly different ways. They all start connections, maintain states, and handle disconnections, but the way they handle timing, acknowledgments, or retries can differ. The Template Method pattern keeps these flows consistent while allowing room for customization.</p>
<p>Inside Android’s Bluetooth stack, you can see this pattern in how connection management is implemented. The process of connecting to a Bluetooth device typically follows the same structure: initialize the stack, attempt a connection, verify success, and then notify other components. Each profile, however, defines its own way of handling the lower-level details.</p>
<p>In conceptual form, it looks something like this:</p>
<pre><code class="lang-java"><span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BluetoothProfileConnection</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">void</span> <span class="hljs-title">connect</span><span class="hljs-params">()</span> </span>{
        prepareConnection();
        performConnection();
        finalizeConnection();
    }

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">void</span> <span class="hljs-title">prepareConnection</span><span class="hljs-params">()</span></span>;
    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">void</span> <span class="hljs-title">performConnection</span><span class="hljs-params">()</span></span>;
    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">void</span> <span class="hljs-title">finalizeConnection</span><span class="hljs-params">()</span></span>;
}
</code></pre>
<p>A class such as <code>A2dpService</code> or <code>GattService</code> would then implement the abstract methods in its own way. One might set up audio channels, while another negotiates attribute protocols. The overall template (prepare, perform, finalize) never changes. This is what keeps the Bluetooth system organized even when dozens of profiles coexist and evolve over time.</p>
<p>This pattern is particularly useful in a codebase as large as Android’s because it enforces discipline without killing flexibility. It ensures that every Bluetooth operation follows the same skeleton, which makes debugging and extending the system far easier. When an engineer wants to add a new feature or fix a connection bug, they already know where to look and which parts are shared or unique.</p>
<p>Another advantage of the Template Method pattern is that it reduces duplication. Without it, each profile might write its own version of “connect,” “disconnect,” and “reconnect,” each slightly different but doing almost the same thing. That would make the code hard to maintain and error-prone. With a template, the core logic lives in one place, and only the necessary variations appear in subclasses.</p>
<p>There is also an important design insight here: Bluetooth, like many communication protocols, is inherently procedural. You must do things in the correct order, initialize before connecting, connect before discovering, and discover before reading data. The Template Method pattern encodes this order directly into the architecture. It prevents accidental mistakes, such as skipping a required step or performing actions out of sequence.</p>
<p>From a broader perspective, this pattern teaches an important engineering lesson about balance. Too much abstraction, and systems become rigid and bureaucratic. Too little structure, and they turn into chaos. The Template Method pattern sits comfortably in the middle. It provides consistency while still leaving space for creativity and variation.</p>
<p>So the next time your phone connects to your car, switches to the right Bluetooth profile, and starts playing music without skipping a beat, you’ll know that there is a quiet choreography happening inside. Each profile follows the same dance steps – prepare, perform, and finalize – but each does it in its own rhythm. That harmony between structure and flexibility is what makes Bluetooth both powerful and adaptable.</p>
<h2 id="heading-the-service-locator-pattern-finding-the-right-profile-at-runtime">The Service Locator Pattern: Finding the Right Profile at Runtime</h2>
<p>At this point, we have seen how Android Bluetooth manages complexity through delegation, structure, and controlled flexibility. But there is still a practical question to answer: with so many Bluetooth services and profiles running in the system (like A2DP, GATT, HFP, MAP, HID, and more), how does the framework know which one to talk to at any given moment? When you stream audio, it needs A2DP. When you sync contacts, it needs PBAP. When you connect a keyboard, it needs HID. Android’s answer to this problem is the <strong>Service Locator</strong> pattern.</p>
<p>In the simplest terms, the Service Locator is a central registry that helps different parts of a system find the service or component they need without having to know where it lives. It’s like the information desk at a large airport. You don’t need to memorize the location of every gate or airline office – you just ask the information desk, and they point you to the right place.</p>
<p>Inside the Android Bluetooth system, this pattern appears everywhere, especially within the <code>AdapterService</code> and <code>BluetoothManagerService</code> classes. These services manage a variety of Bluetooth profiles, and each profile is responsible for its own behavior. Instead of hard-coding every possible profile into every part of the stack, Android maintains a registry where each service can be looked up dynamically.</p>
<p>Here is a simplified version of what this looks like conceptually:</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AdapterService</span> </span>{
    <span class="hljs-keyword">private</span> Map&lt;Integer, ProfileService&gt; mProfileServices = <span class="hljs-keyword">new</span> HashMap&lt;&gt;();

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">registerProfile</span><span class="hljs-params">(<span class="hljs-keyword">int</span> profileId, ProfileService service)</span> </span>{
        mProfileServices.put(profileId, service);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> ProfileService <span class="hljs-title">getProfileService</span><span class="hljs-params">(<span class="hljs-keyword">int</span> profileId)</span> </span>{
        <span class="hljs-keyword">return</span> mProfileServices.get(profileId);
    }
}
</code></pre>
<p>When a Bluetooth operation occurs, such as starting audio streaming or initiating a data transfer, the system asks the AdapterService for the correct profile implementation. The Service Locator then returns the matching service instance, such as the A2DP service for audio or the GATT service for BLE data. Each profile operates independently, but the Service Locator acts as the phonebook that ties them all together.</p>
<p>This pattern solves several key problems. First, it removes the need for every part of the system to know about every other part. Without it, each class would have to keep track of dozens of others, creating a tangled web of dependencies. With a Service Locator, everything becomes more modular. Each component can register itself once and be discovered whenever needed.</p>
<p>Second, it makes the system flexible. Android devices can enable or disable certain Bluetooth profiles depending on hardware support or user configuration. For example, a smartwatch might only need GATT, while a car infotainment system needs A2DP, HFP, and MAP. The Service Locator allows Android to load only the relevant profiles at runtime instead of baking them all in permanently.</p>
<p>Third, it helps with scalability. As new Bluetooth profiles are introduced, such as LE Audio or Broadcast Audio, they can be added without rewriting existing code. The Service Locator acts as the central meeting point that stays the same even as new services join the system. It’s like a well-organized switchboard that never needs rewiring, no matter how many new phones, watches, or speakers show up.</p>
<p>From a debugging standpoint, this design also makes life easier. Developers can trace which service is currently active or verify that a profile is registered correctly simply by inspecting the registry. It provides a single source of truth that reflects the system’s state at any moment.</p>
<p>On a philosophical level, the Service Locator pattern represents Android’s pragmatic approach to complexity. Instead of trying to make every module aware of the entire Bluetooth world, it centralizes coordination in a controlled, predictable way. It acknowledges that Bluetooth is not a single, monolithic feature but an ecosystem of cooperating components that need a shared directory to find each other efficiently.</p>
<p>So when your phone automatically switches from streaming audio over A2DP to transferring a file over OBEX or syncing notifications with your smartwatch, it happens seamlessly because the system always knows exactly which profile to use. That knowledge comes from the quiet work of the Service Locator pattern, acting like a backstage coordinator ensuring that the right performer walks on stage at the right time.</p>
<h2 id="heading-the-layered-architecture-pattern-from-app-to-radio-without-losing-the-plot">The Layered Architecture Pattern: From App to Radio Without Losing the Plot</h2>
<p><img src="https://source.android.com/static/docs/core/connect/bluetooth/images/fluoride_architecture.png" alt="Bluetooth | Android Open Source Project" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>If there is one pattern that truly defines Android’s Bluetooth design philosophy, it is <strong>Layered Architecture</strong>. This is the invisible backbone that keeps the entire system structured, predictable, and scalable. In a world where Bluetooth involves everything from mobile apps to kernel drivers, layering is not just a matter of organization, but one of survival.</p>
<p>At first glance, Bluetooth might seem like a single feature. You turn it on, pair a device, and it works. But in reality, it’s a long, intricate journey that starts at the app layer, where you press “Connect”, and travels all the way down to the radio hardware, which emits electromagnetic signals into the air. Between those two points lies an entire vertical stack of software layers, each playing a distinct role, each isolated from the others by well-defined interfaces.</p>
<p>Think of it as a city with multiple levels. The top layer is where people live and work: that’s your app. Below that are roads and traffic systems, which are your Android framework services. Beneath that, you have subways and utilities, the native daemons written in C and C++ that handle protocol specifics. At the very bottom is the foundation, the hardware abstraction layer and the Bluetooth controller chip itself. Every level has a clear boundary. You can remodel one floor without collapsing the whole building.</p>
<p>Here is how those layers roughly line up in Android’s Bluetooth stack.</p>
<p>At the <strong>top layer</strong>, app developers interact with classes such as <code>BluetoothAdapter</code>, <code>BluetoothDevice</code>, and <code>BluetoothGatt</code>. These are part of the Android framework, written in Java or Kotlin, and serve as the public interface. They provide clean, stable methods like <code>startDiscovery()</code> and <code>connectGatt()</code>, hiding the technical chaos below.</p>
<p>The <strong>next layer down</strong> is the system service layer. This includes classes such as <code>BluetoothManagerService</code> and <code>AdapterService</code>. These are responsible for managing Bluetooth as a system feature, enforcing permissions, and coordinating multiple profiles. They act as the brain of the operation, processing commands, routing messages, and maintaining global state.</p>
<p>Below that is the <strong>JNI and native layer</strong>, written primarily in C and C++. This is where the logic gets closer to the metal. JNI (Java Native Interface) acts as a translator between the Java world and the native code. When a Java method like <code>enable()</code> is called, JNI forwards it to the native daemon that actually speaks Bluetooth protocol commands. This bridge keeps performance high while maintaining safety through strict boundaries.</p>
<p>Finally, we reach the <strong>hardware abstraction layer (HAL)</strong> and the <strong>Bluetooth controller</strong>. The HAL defines how the operating system interacts with the underlying hardware. It sends and receives HCI (Host Controller Interface) packets, the low-level binary messages that control the Bluetooth chip. From there, the controller takes over, turning digital instructions into radio signals that travel invisibly through the air to another device.</p>
<p>The brilliance of this design is in how each layer only needs to know about the one directly below it. The app layer never worries about the hardware, and the hardware never needs to know about the app. This clear separation makes it possible for Android to run across thousands of devices built by different manufacturers using different chipsets. It is a pattern that enforces order through boundaries.</p>
<p>There are practical benefits, too. The layered architecture makes the system modular. For instance, when new Bluetooth features arrive, like LE Audio or Bluetooth 5.4, Android engineers can modify only the relevant layers. The app APIs at the top can remain stable while the lower layers evolve to support the new specifications. This is how Android manages to maintain backward compatibility while still introducing new capabilities with every release.</p>
<p>The layering also helps with debugging and reliability. When something breaks, engineers can trace the issue by moving down through the layers like a detective. If an app crashes, the problem is likely near the top. If packets are missing, the issue may be in the native layer or HAL. Each layer leaves its own signature in the logs, helping developers pinpoint where things went wrong.</p>
<p>This pattern also teaches a timeless software design lesson: complexity becomes manageable only when divided. The layered architecture prevents the Bluetooth stack from turning into a tangled mess of cross-dependencies. It lets Android evolve gracefully rather than collapse under the weight of its own history.</p>
<p>So when you tap “Pair new device” on your phone and watch your earbuds connect, remember that your request travels down a carefully organized highway of software, from the app you see, through the framework, into native code, across the hardware abstraction, and finally out into the air as a radio signal. Every piece knows its role, every layer does its part, and together they make Bluetooth feel effortless. The magic of wireless connection is not just in the radio waves, but in the architecture that makes those waves behave.</p>
<h2 id="heading-putting-it-all-together-designing-bluetooth-style-systems">Putting It All Together: Designing Bluetooth-Style Systems</h2>
<p>By now, it’s easy to see that Android’s Bluetooth stack is not just a pile of random services and classes. It’s a carefully choreographed system built on timeless design principles that keep it reliable, flexible, and surprisingly elegant despite its complexity.</p>
<p>Each pattern – the Manager–Service split, the Facade, the State Machine, the Handler–Looper, the Observer, the Builder, the Strategy, the Template Method, the Service Locator, and the Layered Architecture – exists for a reason. Together, they form the invisible scaffolding that allows Bluetooth to connect billions of devices every day without falling apart.</p>
<p>The magic of these patterns is not that they make Bluetooth simple. Bluetooth will never be simple, as it’s an enormous specification with quirks, edge cases, and competing priorities. What these patterns do instead is make the system <strong>manageable</strong>. They turn unpredictability into structure, they replace chaos with order, and they make it possible for teams of engineers around the world to work on the same stack without tripping over each other.</p>
<p>If you step back, you’ll notice that every pattern in the Bluetooth system reflects a deeper philosophy:</p>
<ul>
<li><p>The Manager–Service pattern teaches the value of separation.</p>
</li>
<li><p>The Facade reminds us that good design hides unnecessary complexity.</p>
</li>
<li><p>The State Machine shows the power of predictability.</p>
</li>
<li><p>The Handler–Looper demonstrates the beauty of serialized concurrency.</p>
</li>
<li><p>The Observer proves that communication doesn’t require coupling.</p>
</li>
<li><p>The Builder celebrates incremental construction.</p>
</li>
<li><p>The Strategy encourages adaptability.</p>
</li>
<li><p>The Template Method enforces discipline without rigidity.</p>
</li>
<li><p>The Service Locator maintains organization in a crowded ecosystem.</p>
</li>
<li><p>And the Layered Architecture ties it all together, ensuring that every piece fits logically into the whole.</p>
</li>
</ul>
<p>These same ideas extend far beyond Bluetooth. You can apply them to almost any software system, a web service, a game engine, or even a simple mobile app. The principles remain the same: divide responsibilities, enforce clear boundaries, keep your interfaces stable, and design for change rather than permanence.</p>
<p>Systems that last are not the ones that are perfect on day one. They are the ones that can grow without collapsing under their own weight.</p>
<p>Android Bluetooth has been evolving for more than a decade. It has absorbed new technologies like LE Audio, Fast Pair, and broadcast audio. It has adapted to new hardware, new chipsets, and new use cases. Yet, at its core, the same patterns continue to guide it. That consistency is the reason Bluetooth on Android, despite its quirks, works as well as it does. It’s not just a story of wireless communication, it’s a story of good architecture.</p>
<p>So the next time you tap “Connect” on your phone and your earbuds instantly respond, pause for a moment. Beneath that single tap lies an orchestra of design patterns working in perfect harmony: managers delegating to services, handlers processing messages, observers reacting to broadcasts, and strategies choosing the right behavior for your hardware. It’s a quiet miracle of software design, a reminder that even the most invisible features on your device are built with care, patience, and an eye for long-term evolution.</p>
<p>And if you ever find yourself building a complex system that seems impossible to manage, take a cue from Android Bluetooth. Start small, define your layers, choose the right patterns, and let structure do the heavy lifting. The real magic in engineering isn’t in writing clever code. It’s in designing systems that stay calm, even when the world around them isn’t.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use the Compound Components Pattern in React: Prop Soup to Flexible UIs ]]>
                </title>
                <description>
                    <![CDATA[ Have you ever opened React project source code and wondered why things are so messy? Have you ever tried adding a feature to a React component created by someone else and felt that you needed to rewrite it? Have you felt nightmarish in tackling state... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/compound-components-pattern-in-react/</link>
                <guid isPermaLink="false">68e70e0ecfc3d2834515166c</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ design patterns ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Tapas Adhikary ]]>
                </dc:creator>
                <pubDate>Thu, 09 Oct 2025 01:21:18 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1759972853846/49e605c8-be15-44a4-9fc6-283be0cc0e4c.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Have you ever opened React project source code and wondered why things are so messy? Have you ever tried adding a feature to a React component created by someone else and felt that you needed to rewrite it? Have you felt nightmarish in tackling state and props for a component and its children?</p>
<p>If you happen to shout out “Yes!” to the above, you’re not alone. It’s a common feeling among many React developers across the globe. But React itself is not responsible for any of these issues. These situations arise because of code smells like:</p>
<ul>
<li><p>Props drilled six levels down.</p>
</li>
<li><p>A single bloated component doing everything.</p>
</li>
<li><p>Logic that’s duplicated across different components.</p>
</li>
<li><p>Careless rendering (and re-rendering) causing performance issues.</p>
</li>
</ul>
<p>A <code>Code Smell</code> doesn’t mean broken code. Rather, it’s an indication that the code may work now, but is difficult to maintain, reuse, scale, and much harder to debug.</p>
<p>And that’s exactly where we need to use <code>Design Patterns</code>. They’re well-tested solutions to the various code smell problems that developers have been encountering for decades. When you know how to use them well, you achieve a clean, maintainable codebase that is easy to enhance, debug, and scale.</p>
<p>Today, we will take a deep dive into one of the most prominent design patterns in React called the <code>Compound Components Pattern</code>. This pattern saves React developers from passing a long list of props and helps build composable user interface components.</p>
<p>This is going to be a complete hands-on tutorial. So get your favourite code editor ready, and let’s get started. This article is also available as a video tutorial as part of the <a target="_blank" href="https://www.youtube.com/playlist?list=PLIJrr73KDmRyQVT__uFZvaVfWPdfyMFHC">15 Days of React Design Patterns</a> initiative. Please check it out.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/LglWulOqh6k" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-react-19-code-set-up">React 19 Code Set Up</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-a-messy-modal-component">A Messy Modal Component</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-problems-with-this-messy-modal-component">The Problems with this messy Modal Component</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-compound-components-pattern">The Compound Components Pattern</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-a-modal-component-using-the-compound-components-pattern">How to Build a Modal Component using the Compound Components Pattern</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-why-didnt-we-create-separate-files-for-the-subcomponents">Why Didn’t We Create Separate Files for the SubComponents?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-the-modal-component">How to Use the Modal Component</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-an-accordion-component-using-the-compound-components-pattern">How to build an Accordion Component using the Compound Components Pattern</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-add-the-accordion-to-the-modal">Add the Accordion to the Modal</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-the-use-cases">The Use Cases</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-pitfalls-and-anti-patterns">The Pitfalls and Anti-Patterns</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-15-days-of-react-patterns">15 Days of React Design Patterns</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-before-we-end">Before We End...</a></p>
</li>
</ol>
<h2 id="heading-react-19-code-set-up">React 19 Code Set Up</h2>
<p>The best way to understand how to apply a design pattern is by refactoring messy code with code smells to improve it to cleaner code. So let’s set up a coding ground so that we can start putting in our messy code first, and then go about applying the design pattern to it.</p>
<p>Note: you can find all the source code used in this tutorial on the <a target="_blank" href="https://github.com/tapascript/15-days-of-react-design-patterns/tree/main/day-03/compound-components-patterns">tapaScript GitHub</a>. Feel free to follow along with it side by side.</p>
<p>Also, make sure you have Node.js installed (preferably v18+). You can check it out by typing this command on your terminal/command prompt:</p>
<pre><code class="lang-bash">node -v
</code></pre>
<p>If you get an output with the installed Node.js version, you are all set. Otherwise, just download and install Node.js from <a target="_blank" href="https://nodejs.org/en/download">here</a>.</p>
<p>Now, run this command in your terminal to create a React 19 project scaffolding:</p>
<pre><code class="lang-bash">npx degit atapas/code-in-react-19<span class="hljs-comment">#main compound-components-pattern</span>
</code></pre>
<p>It will create a folder called <code>compound-components-pattern</code> with the Vite-based React project files under it. Now, change the directory using this command:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> compound-components-pattern
</code></pre>
<p>Then install the dependencies using this command:</p>
<pre><code class="lang-bash">npm install <span class="hljs-comment">## Or, yarn install, or pnpm install, etc,</span>
</code></pre>
<p>Now, you can import the project folder into your favourite code editor (I use VS Code).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1759478983493/692ac0f9-4780-4d60-bc72-55f27b9a6074.png" alt="Code Scaffolding" class="image--center mx-auto" width="481" height="552" loading="lazy"></p>
<p>Finally, to start the project locally, use the following command:</p>
<pre><code class="lang-bash">npm run dev <span class="hljs-comment">## Or, yarn dev, or pnpm dev</span>
</code></pre>
<p>Now the project should be running locally and should be accessible on the default URL, <a target="_blank" href="http://localhost:5173"><code>http://localhost:5173</code></a>. You can access the URL in your browser. Now we’re all set to start coding.</p>
<h2 id="heading-a-messy-modal-component">A Messy Modal Component</h2>
<p>Let’s get started by creating a Modal component. Start by creating a directory called <code>messy</code> under the <code>src/</code> directory. Now, create a file called <code>Modal.jsx</code> under <code>src/messy/</code> with the following code snippet:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Modal</span>(<span class="hljs-params">{ title, body, primaryAction, secondaryAction }</span>) </span>{
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"modal-backdrop"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"modal-container"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"modal-header"</span>&gt;</span>{title}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"modal-body"</span>&gt;</span>{body}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"modal-footer"</span>&gt;</span>
                    {secondaryAction}
                    {primaryAction}
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Modal;
</code></pre>
<p>This is a simple React implementation of a modal component that accepts a title, body, and a couple of actions as props to render them as a modal.</p>
<ul>
<li><p>The <code>title</code>: The header title of the modal.</p>
</li>
<li><p>The <code>body</code>: The modal content.</p>
</li>
<li><p>The <code>primaryAction</code>: An action button like delete, create, save, and so on to place in the footer section of the modal.</p>
</li>
<li><p>The <code>secondaryAction</code>: An action button like cancel, close, and so on to place in the footer section of the modal.</p>
</li>
</ul>
<p>Next, open the <code>App.jsx</code> file and replace the existing code with the following code snippet:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Modal <span class="hljs-keyword">from</span> <span class="hljs-string">"./messy/Modal"</span>;

<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col items-center"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Modal</span>
                <span class="hljs-attr">title</span>=<span class="hljs-string">"Delete Account"</span>
                <span class="hljs-attr">body</span>=<span class="hljs-string">"Are you sure you want to delete your account?"</span>
                <span class="hljs-attr">primaryAction</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">button</span>&gt;</span>Delete<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>}
                secondaryAction={<span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Cancel<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>} /&gt;
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Here, we have imported the <code>Modal</code> component and used it by passing its props values. Go to the browser tab and access the app’s URL. You should see the modal appearing like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1759409687600/825901e9-5b38-49a7-8d7d-74a0867f6a01.png" alt="messy modal without style" class="image--center mx-auto" width="2172" height="1312" loading="lazy"></p>
<p>Well, as it doesn’t look like a traditional modal with a backdrop and all, so let’s fix that using CSS. Open the <code>App.css</code> and paste the following CSS styles into it and save it:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.modal-backdrop</span> {
    <span class="hljs-attribute">position</span>: fixed;
    <span class="hljs-attribute">inset</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">background</span>: <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.5</span>);
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">justify-content</span>: center;
    <span class="hljs-attribute">align-items</span>: center;
}
<span class="hljs-selector-class">.modal-container</span> {
    <span class="hljs-attribute">background</span>: white;
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">8px</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">400px</span>;
    <span class="hljs-attribute">position</span>: relative;
}
<span class="hljs-selector-class">.modal-header</span> {
    <span class="hljs-attribute">font-weight</span>: bold;
    <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">1rem</span>;
}
<span class="hljs-selector-class">.modal-footer</span> {
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">justify-content</span>: flex-end;
    <span class="hljs-attribute">gap</span>: <span class="hljs-number">0.5rem</span>;
    <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">1rem</span>;
}
<span class="hljs-selector-class">.modal-close</span> {
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">top</span>: <span class="hljs-number">8px</span>;
    <span class="hljs-attribute">right</span>: <span class="hljs-number">8px</span>;
    <span class="hljs-attribute">background</span>: none;
    <span class="hljs-attribute">border</span>: none;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.2rem</span>;
}
</code></pre>
<p>Great! Now you have a cool-looking modal dialog asking for your confirmation to delete your account.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1759409736382/ceaaa23e-26d3-4d7d-93ed-ae83aa69b421.png" alt="Messy Modal with style" class="image--center mx-auto" width="2170" height="1314" loading="lazy"></p>
<h2 id="heading-the-problems-with-this-messy-modal-component">The Problems with This Messy Modal Component</h2>
<p>Question for you: What problems do you think this modal implementation might have?</p>
<p>Let’s find the answers:</p>
<ol>
<li><p><code>Lack of Flexibility</code>: The modal has a rigid structure that dictates exactly what it renders. What if you want a modal without a title? Or a modal with a custom layout? Or more than two action buttons? You need to write additional logic and pass additional props every time you think of enhancing the modal for another use case. These changes in the component will bring maintainability issues and increase code smell.</p>
</li>
<li><p><code>Mixed Responsibilities</code>: The modal tries to do multiple things. It handles both layout and content. This violates the separation of concerns principle that we learn from other design patterns, such as the <a target="_blank" href="https://www.youtube.com/watch?v=1UHbhikwg-s">Container-Presenter Pattern</a>.</p>
</li>
<li><p><code>Hard Reusability</code>: The modal lacks reusability due to its rigidness. Right now, if you want a modal with this:</p>
<pre><code class="lang-javascript"> &lt;h2&gt;Something Wrong!&lt;/h2&gt;
 <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"warning.png"</span> /&gt;</span></span>
 <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Something went wrong. please see the logs for more details.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
</code></pre>
<p> You can not reuse this component, and you will end up creating a new one.</p>
</li>
<li><p><code>Poor Scalability</code>: The modal component is not scalable. Think, for example, if you’re creating a component library and you end up creating multiple modal instances like ConfirmationModal, InfoModal, FormModal, ImageModal, and so on. It would be a huge ding on the scalability of that component library to create and maintain every new version of the modal.</p>
</li>
<li><p><code>Hard to Test</code>: This modal implementation is hard to test due to its tight coupling with props.</p>
</li>
</ol>
<p>With these issues in mind, let’s welcome the compound components pattern and see how it can help us solve them.</p>
<h2 id="heading-the-compound-components-pattern">The Compound Components Pattern</h2>
<p><code>Compound Components Pattern</code> in React is a design pattern where a parent component works together with its child components to share an implicit state and behaviour. Instead of passing a long list of props, the parent manages the state and exposes flexible child components (&lt;Modal.Header&gt;, &lt;Modal.Body&gt;, &lt;Modal.Footer&gt;, and so on) so that consumers can compose the UI naturally, just like using native HTML elements.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1759409949714/8144535d-c0f3-4ae7-bd8d-ab93fe7bf6c2.png" alt="Compound Components Pattern Diagram" class="image--center mx-auto" width="2572" height="1238" loading="lazy"></p>
<p>Think of Compound Composition Pattern like LEGO blocks.</p>
<ul>
<li><p>The parent component is like the LEGO base plate.</p>
</li>
<li><p>The child components are the LEGO blocks (door, window, roof, and so on).</p>
</li>
<li><p>You don’t pass any props to the base plate, saying, <em>“add a door here, add a window there.”</em> Instead, you simply place the pieces where you want them.</p>
</li>
<li><p>The base plate (parent) still provides the rules and structure (studs, alignment, stability), but you get the flexibility to assemble your model however you like.</p>
</li>
</ul>
<p>Got it? That’s the power of compound components. It’s a flexible composition with a shared state/behaviour underneath.</p>
<p>Let’s now refactor our messy (and smelly) modal component by applying the compound components pattern.</p>
<h2 id="heading-how-to-build-a-modal-component-using-the-compound-components-pattern">How to Build a Modal Component Using the Compound Components Pattern</h2>
<p>Create a folder called <code>with-pattern</code> under the <code>src/</code> folder. We will arrange and maintain the modal component, and in the future, an accordion component under this new folder.</p>
<p>Next, create a folder called <code>modal</code> under the <code>src/with-pattern</code>. Finally, create a file called <code>Modal.jsx</code> with the following code snippet:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// File Location: src/with-pattern/modal/Modal.jsx</span>

<span class="hljs-keyword">const</span> Modal = <span class="hljs-function">(<span class="hljs-params">{ children, isOpen, onClose }</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span>(!isOpen) <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"modal-backdrop"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"modal-container"</span>&gt;</span>
                {children}
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"modal-close"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onClose}</span>&gt;</span>
                    ✖
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
};

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ModalHeader</span>(<span class="hljs-params">{ children }</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"modal-header"</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ModalBody</span>(<span class="hljs-params">{ children }</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"modal-body"</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ModalFooter</span>(<span class="hljs-params">{ children }</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"modal-footer"</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}

Modal.Header = ModalHeader;
Modal.Body = ModalBody;
Modal.Footer = ModalFooter;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Modal;
</code></pre>
<p>Let me break it down for you:</p>
<ul>
<li><p>First, focus on the Modal component above. It doesn’t take title, body, and so on as props anymore. Rather, it accepts <code>children</code>, a special prop in React to pass any HTML elements, a group of HTMLs, JSX, or even a React component. It brings flexibility that we are no longer fixed to any particular structure to pass to the Modal component.</p>
</li>
<li><p>The JSX of the Modal component just renders the <code>children</code> prop as is, giving the entire power to the consumer of the Modal component to pass any structure it’s willing to. The Modal component uses the backdrop and container style to dictate the basic look and feel of a modal.</p>
</li>
<li><p>The Modal’s JSX also has a button to close the modal by clicking on an x. To open and close the modal, we have passed two additional props, <code>isOpen</code> and <code>onClose</code>. You can imagine <code>isOpen</code> is a state value that the consumer of this modal uses to open the modal, and the <code>onClose</code> is a function that sets the value of the <code>isOpen</code> to false to close the modal.</p>
</li>
<li><p>Then, we have defined three more components, <code>ModalHeader</code>, <code>ModalBody</code>, and <code>ModalFooter</code> which are equally flexible to accept any legit HTML structure or React component through the <code>children</code> prop. Now you can pass anything to render to the modal header. The same goes for the body and footer as well.</p>
</li>
<li><p>Next, we add the header, body, and footer as the subcomponents to the <code>Modal</code> component.</p>
<pre><code class="lang-javascript">  Modal.Header = ModalHeader;
  Modal.Body = ModalBody;
  Modal.Footer = ModalFooter;
</code></pre>
</li>
<li><p>Finally, we exported the <code>Modal</code> component.</p>
</li>
</ul>
<h3 id="heading-why-didnt-we-create-separate-files-for-the-subcomponents">Why Didn’t We Create Separate Files for the SubComponents?</h3>
<p>This question is quite natural. In general, we follow the standard practice of one component in one source file(.jsx/.tsx). Here, we seem to be breaking that rule…so are we? Actually not.</p>
<p>The golden rules are:</p>
<ul>
<li><p>The subcomponents (ModalHeader, ModalBody, and ModalFooter) are only meaningful in the context of Modal. They don’t have (or need) any existence beyond the modal.</p>
</li>
<li><p>They are small helper components that you don’t expect to reuse anywhere else.</p>
</li>
<li><p>Keeping them together is good for discoverability and is safe from potential misuse that we’ll discuss in the pitfalls section later.</p>
</li>
</ul>
<h3 id="heading-how-to-use-the-modal-component">How to Use the Modal Component</h3>
<p>So we’re sorted. Let’s now learn how to use this Modal component and see how it can bring flexibility, reusability, scalability, and testability.</p>
<p>Open the <code>App.jsx</code> file and replace the content of it with the following code snippet:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-comment">// import Modal from "./messy/Modal";</span>
<span class="hljs-keyword">import</span> Modal <span class="hljs-keyword">from</span> <span class="hljs-string">"./with-pattern/modal/Modal"</span>;

<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [isOpen, setIsOpen] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col items-center"</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsOpen(true)}&gt;Open Modal<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">Modal</span> <span class="hljs-attr">isOpen</span>=<span class="hljs-string">{isOpen}</span> <span class="hljs-attr">onClose</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsOpen(false)}&gt;

        <span class="hljs-tag">&lt;<span class="hljs-name">Modal.Header</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Welcome!<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Modal.Header</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">Modal.Body</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
              This is a modal built with the Compound Component
              pattern.
          <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Modal.Body</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">Modal.Footer</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Help!<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsOpen(false)}&gt;Close<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> alert("Action Performed!")}&gt;Do Action<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Modal.Footer</span>&gt;</span>

      <span class="hljs-tag">&lt;/<span class="hljs-name">Modal</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Check out how we have passed a bunch of JSX inside &lt;Modal&gt;…&lt;/Modal&gt; as the children. It’s so powerful. We’re passing the subcomponents header, body, and footer in the sequence we want them to appear in the modal.</p>
<p>Next, if we look into the &lt;ModalHeader&gt;, &lt;ModalBody&gt;, or &lt;ModalFooter&gt; components, we can again pass anything as children to them. For example, the &lt;ModalFooter /&gt; can now take three buttons (in fact, anything else) based on the needs.</p>
<p>We can compose the components like Lego blocks to build the kind of Modal that we wish to. You don't need to have different components to represent different kinds of modals now. This single component can cater to all your modal needs without introducing any props soup drama.</p>
<p>We have a button to open the modal, and the App.jsx component manages a state called <code>isOpen</code> to tackle the opening and closing of the modal.</p>
<p>You should be able to see these changes now in the browser. Click on the open modal button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1759410185904/b7adbab0-9d24-4245-92ad-84766817af12.png" alt="Open Modal Button" class="image--center mx-auto" width="1528" height="964" loading="lazy"></p>
<p>The modal dialog opens up with all the content we have passed to it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1759410275413/9bff6791-3cf8-45eb-aea8-a85e9a95777d.png" alt="Modal With Pattern" class="image--center mx-auto" width="1892" height="1280" loading="lazy"></p>
<p>It’s a big leap towards achieving clean code to use the compound components design pattern. Now that you’re familiar with the basics, let’s quickly do another classic implementation of this pattern by building an Accordion component.</p>
<h2 id="heading-how-to-build-an-accordion-component-using-the-compound-components-pattern">How to Build an Accordion Component Using the Compound Components Pattern</h2>
<p>An accordion component is an array of Accordion Items. It’s a combination of a header and body that shows and hides the content when users click on the header.</p>
<p>Create a folder called <code>accordion</code> under <code>src/with-pattern</code> folder. Now, create a file called <code>Accordion.jsx</code> inside the <code>src/with-pattern/accordion</code> with the following code snippet:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Accordion</span>(<span class="hljs-params">{ children }</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion"</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">AccordionItem</span>(<span class="hljs-params">{ title, children }</span>) </span>{
  <span class="hljs-keyword">const</span> [isOpen, setIsOpen] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion-item"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion-title"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsOpen(!isOpen)}&gt;
        {title}
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      {isOpen &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"accordion-content"</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Attach subcomponents</span>
Accordion.Item = AccordionItem;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Accordion;
</code></pre>
<p>Here,</p>
<ul>
<li><p>We have followed the same pattern as we did for the modal previously. We have an <code>Accordion</code> component that takes a special prop called <code>children</code>, enabling the Accordion to accept any HTML/JSX/React component and render it.</p>
</li>
<li><p>Then we defined the <code>AccordionItem</code>. It takes two props: the title to create the header, and the special prop called children to form the accordion content flexibly.</p>
</li>
<li><p>The header is formed using the button that is driven by a state called <code>isOpen</code> to show/hide the content area.</p>
</li>
<li><p>The content area of an <code>AccordionItem</code> could be anything: a paragraph, a table, an image, or even a JSX combining them.</p>
</li>
<li><p>Finally, we have added the AccordionItem as the subcomponent to the Accordion component.</p>
</li>
</ul>
<p>To make the accordion look better, let’s add a few styles. Open the <code>App.css</code> file and add these styles at the end of the file:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.accordion-item</span> {
    <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">0.5rem</span>;
    <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#ddd</span>;
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">4px</span>;
}
<span class="hljs-selector-class">.accordion-title</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">text-align</span>: left;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.5rem</span>;
    <span class="hljs-attribute">font-weight</span>: bold;
    <span class="hljs-attribute">cursor</span>: pointer;
    <span class="hljs-attribute">background</span>: <span class="hljs-number">#f9f9f9</span>;
    <span class="hljs-attribute">border</span>: none;
}
<span class="hljs-selector-class">.accordion-content</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.5rem</span>;
    <span class="hljs-attribute">background</span>: <span class="hljs-number">#fff</span>;
}
</code></pre>
<p>Great, let’s now use the Accordion component. Create a new file called <code>AccordionDemo.jsx</code> under the folder <code>src/with-pattern/accordion</code> with the following code snippet:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Accordion <span class="hljs-keyword">from</span> <span class="hljs-string">"./Accordion"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">AccordionDemo</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Accordion</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Accordion.Item</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"What is Compound Component Pattern?"</span>&gt;</span>
        It’s a React pattern that allows parent and child components to work
        together seamlessly while giving developers flexible composition.
      <span class="hljs-tag">&lt;/<span class="hljs-name">Accordion.Item</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">Accordion.Item</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Why use it?"</span>&gt;</span>
        It makes UI libraries like modals, tabs, accordions, menus, etc. easier
        to build and use.
      <span class="hljs-tag">&lt;/<span class="hljs-name">Accordion.Item</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">Accordion.Item</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Pitfalls?"</span>&gt;</span>
        Overusing it can lead to deeply nested structures or make things harder
        to debug if not documented well.
      <span class="hljs-tag">&lt;/<span class="hljs-name">Accordion.Item</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Accordion</span>&gt;</span></span>
  );
}
</code></pre>
<p>Check out how the <code>Accordion</code> component can accept a bunch of AccordionItem components. You can also create an array of <code>AccordionItem</code> components and pass them dynamically to the Accordion component.</p>
<p>Each of the AccordionItem components accepts the title prop value, and we passed the text as the children. If needed, you can pass any other valid JSX as a child. That’s amazing!</p>
<h3 id="heading-add-the-accordion-to-the-modal">Add the Accordion to the Modal</h3>
<p>Now, let’s take the usage of this pattern to the next level. How about using the <code>AccordionDemo</code> inside the <code>Modal</code> component? Can we do it without changing the Modal component?</p>
<p>Oh yes! Remember, the Modal component accepts any JSX as children, and so does the ModalBody component. So we can just import the AccordionDemo component into the App.jsx file and use it inside the &lt;Modal.Body&gt;…&lt;/Modal.Body&gt; as shown below, right?</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-comment">// import Modal from "./messy/Modal";</span>
<span class="hljs-keyword">import</span> Modal <span class="hljs-keyword">from</span> <span class="hljs-string">"./with-pattern/modal/Modal"</span>;

<span class="hljs-keyword">import</span> AccordionDemo <span class="hljs-keyword">from</span> <span class="hljs-string">"./with-pattern/accordion/AccordionDemo"</span>;

<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [isOpen, setIsOpen] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col items-center"</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsOpen(true)}&gt;Open Modal<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">Modal</span> <span class="hljs-attr">isOpen</span>=<span class="hljs-string">{isOpen}</span> <span class="hljs-attr">onClose</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsOpen(false)}&gt;

        <span class="hljs-tag">&lt;<span class="hljs-name">Modal.Header</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Welcome!<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Modal.Header</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">Modal.Body</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
              This is a modal built with the Compound Component
              pattern.
          <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">AccordionDemo</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Modal.Body</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">Modal.Footer</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Help!<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsOpen(false)}&gt;Close<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> alert("Action Performed!")}&gt;Do Action<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Modal.Footer</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Modal</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Now, if you run the app with these code changes, you should see the accordion appearing inside the modal. You will also be able to show/hide the accordion content and open/close the modal. This means their individual states are intact as expected.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1759410454778/69fdcb6a-77a0-42e1-b060-fa2666543c94.png" alt="Accordion" class="image--center mx-auto" width="1902" height="1280" loading="lazy"></p>
<h2 id="heading-the-use-cases">The Use Cases</h2>
<p>So far, we have seen a couple of important usages of the Compound Components pattern with modal and accordion. Similarly, you can use this pattern to build reusable components like:</p>
<ul>
<li><p>Tables (Table.Head, Table.Body, Table.Row).</p>
</li>
<li><p>Any component where layout and nesting matter.</p>
</li>
</ul>
<p>Also, if you’re ever writing your own component library or design system, this pattern is a must. If you need some inspiration, look at ShadCN, Material UI, or Radix UI. They all do this.</p>
<h2 id="heading-the-pitfalls-and-anti-patterns">The Pitfalls and Anti-Patterns</h2>
<p>As you know, with great power comes great responsibility. And with patterns comes the pitfalls and anti-patterns you’ll need to be aware of. When you’re using the compound components pattern, just make sure that you:</p>
<ul>
<li><p>Don’t attach subcomponents randomly. They should belong to the parent semantically.</p>
</li>
<li><p>Avoid re-exporting subcomponents separately. It will be a disaster if someone uses the ModalFooter without a Modal. What if the ModalFooter changes tomorrow in the context of the Modal, and the other consumers are not in need/aware of that change?</p>
</li>
<li><p>Don’t attempt to make everything in the compound components pattern. The rule of thumb is, only use it when the children's structure matters, and you want to keep it flexible.</p>
</li>
</ul>
<h2 id="heading-15-days-of-react-design-patterns">15 Days of React Design Patterns</h2>
<p>I have some great news for you! After the <em>40 days of the JavaScript</em> initiative, I have now started a brand new initiative called <a target="_blank" href="https://www.youtube.com/playlist?list=PLIJrr73KDmRyQVT__uFZvaVfWPdfyMFHC">15 Days of React Design Patterns</a>.</p>
<p>If you enjoyed learning from this article, I am sure you will love this series, featuring the 15 most important React design patterns. Check it out and join.</p>
<p><a target="_blank" href="https://www.youtube.com/playlist?list=PLIJrr73KDmRyQVT__uFZvaVfWPdfyMFHC"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1759482303884/694491a4-2fd9-4515-b595-eafc925d2a18.png" alt="15 Days of React Design Patterns" class="image--center mx-auto" width="1557" height="820" loading="lazy"></a></p>
<h2 id="heading-before-we-end"><strong>Before We End...</strong></h2>
<p>That’s all! I hope you found this article insightful.</p>
<p>Let’s connect:</p>
<ul>
<li><p>Subscribe to my <a target="_blank" href="https://www.youtube.com/tapasadhikary?sub_confirmation=1">YouTube Channel</a>.</p>
</li>
<li><p>Subscribe to my fortnightly newsletter, <a target="_blank" href="https://tapascript.substack.com/subscribe?utm_medium=fcc">The Commit Log</a>.</p>
</li>
<li><p>Follow on <a target="_blank" href="https://www.linkedin.com/in/tapasadhikary/">LinkedIn</a> if you don't want to miss the daily dose of up-skilling tips.</p>
</li>
<li><p>Join my <a target="_blank" href="https://discord.gg/zHHXx4vc2H">Discord Server</a>, and let’s learn together.</p>
</li>
</ul>
<p>See you soon with my next article. Until then, please take care of yourself and keep learning.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Object-Oriented Design Patterns with Java ]]>
                </title>
                <description>
                    <![CDATA[ In this article I will introduce some of the most useful object-oriented design patterns. Design patterns are solutions to common problems that show up over and over again. These problems will show up in many different contexts but always have the sa... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/object-oriented-design-patterns-with-java/</link>
                <guid isPermaLink="false">6887df408810970f0e04fae6</guid>
                
                    <category>
                        <![CDATA[ design patterns ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Java ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Mark Mahoney ]]>
                </dc:creator>
                <pubDate>Mon, 28 Jul 2025 20:36:16 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1753734965769/4d53f28e-7d85-4571-831f-1760490e06dc.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article I will introduce some of the most useful object-oriented <a target="_blank" href="https://www.freecodecamp.org/news/javascript-design-patterns-explained/">design patterns</a>. Design patterns are solutions to common problems that show up over and over again. These problems will show up in many different contexts but always have the same problem at the root.</p>
<p>A design pattern attempts to describe an effective solution to the problem in a generic way so that it can be applied to a specific set of circumstances.</p>
<p>I will use Java to build an example of each pattern. I’m assuming that you have some programming experience in Java. In particular, you should be (at least somewhat) familiar with the concepts of inheritance and polymorphism. These design patterns really show the power of inheritance and polymorphism, so if you are just learning about these topics this is a great opportunity to dig deeper.</p>
<p>What if you not a Java programmer? If you are familiar with any Object-Oriented language you will probably still get a lot out of the examples. Give it a shot!</p>
<h2 id="heading-code-playbacks"><strong>Code Playbacks</strong></h2>
<p>To make design patterns more approachable, I developed an interactive tutorial that uses annotated <a target="_blank" href="https://markm208.github.io/"><strong>code playbacks</strong></a> to walk through key design pattern features step-by-step.</p>
<p>Each design pattern is presented as a code playback that shows how a program changes over time along with my explanation about what's happening. This format helps you focus on the reasoning behind the code changes.</p>
<p>You can access the free 'book' of code playbacks here:</p>
<blockquote>
<p><a target="_blank" href="https://playbackpress.com/books/patternsbook">OO Design Patterns with Java</a>, by Mark Mahoney (that’s me)</p>
</blockquote>
<p>To view a code playback, click on the comments in the left panel. Each comment updates the code in the editor and highlights any changes. Read the explanation and study the code. If you get stuck, use the AI assistant like a tutor to help explain what is happening in the code.</p>
<p>For more information about code playbacks, you can watch a short demo here.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/uYbHqCNjVDM" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<h2 id="heading-key-design-patterns-you-should-know">Key Design Patterns You Should Know</h2>
<h3 id="heading-strategy-pattern"><strong>Strategy Pattern</strong></h3>
<p>The <a target="_blank" href="https://www.freecodecamp.org/news/a-beginners-guide-to-the-strategy-design-pattern/"><strong>Strategy Pattern</strong></a> is used to define a 'family' of algorithms, encapsulate each one, and make them interchangeable. Software developers use the Strategy pattern when they know there are many different ways of accomplishing some behavior. Rather than include all the different ways in a single class, they separate them out into individual classes and plug them in when necessary.</p>
<p>This program creates some classes to hold student grades. Some instructors like to adjust the entire course’s grades to make them higher. Some instructors do this by dropping every student's lowest grade. Other instructors 'curve' each assignment. Since there are several different options, I will use the <strong>Strategy Pattern</strong> to isolate them and let the client choose which one they prefer.</p>
<p>Start by looking at the <code>Assignment</code>, <code>Student</code>, and <code>Course</code> classes. Once you are familiar with the core classes, watch as I change the code to implement two different approaches to <em>curving</em> the grades using the <strong>Strategy Pattern</strong>:</p>
<blockquote>
<p><a target="_blank" href="https://playbackpress.com/books/patternsbook/chapter/1/1"><strong>Strategy Pattern</strong> Adjusting Grades in a Course</a></p>
</blockquote>
<h3 id="heading-singleton-pattern"><strong>Singleton Pattern</strong></h3>
<p>There are times when you need to make sure there is only one instance of a class and it is accessible everywhere in your code. This is the problem that the <a target="_blank" href="https://en.wikipedia.org/wiki/Singleton_pattern"><strong>Singleton Pattern</strong></a> solves.</p>
<p>In this program, I will create a class that generates random numbers. I will rely on Java's built-in <code>Random</code> class but will be able to reproduce the exact same sequence of random numbers when in 'test mode'. I'll make sure that there is only one instance of this random number generator using the <strong>Singleton Pattern</strong>:</p>
<blockquote>
<p><a target="_blank" href="https://playbackpress.com/books/patternsbook/chapter/1/2"><strong>Singleton Pattern</strong> A Testable Random Number Class</a></p>
</blockquote>
<h3 id="heading-composite-pattern"><strong>Composite Pattern</strong></h3>
<p>Often, we’ll create whole/part containment tree structures. For example, in a file system there are simple files. I call these simple elements, <em>primitives</em>. We can group primitives together to form larger <em>composites</em>. Files can be grouped into directories. These composites (directories) can be grouped into still larger composites, and so on.</p>
<p>We could treat composites and primitives differently. But it often makes sense to treat them the same. Having to distinguish between the object types makes the application more complex.</p>
<p>The <a target="_blank" href="https://en.wikipedia.org/wiki/Composite_pattern"><strong>Composite Pattern</strong></a> describes how to use recursive composition so that clients don't need to make this distinction.</p>
<p>This program creates classes for printing a hierarchical collection of files and directories using the <strong>Composite Pattern</strong>:</p>
<blockquote>
<p><a target="_blank" href="https://playbackpress.com/books/patternsbook/chapter/1/3"><strong>Composite Pattern</strong> Displaying a Hierarchical File System</a></p>
</blockquote>
<h3 id="heading-decorator-pattern"><strong>Decorator Pattern</strong></h3>
<p>Sometimes we want to add responsibilities to individual objects, not an entire class. The <a target="_blank" href="https://en.wikipedia.org/wiki/Decorator_pattern"><strong>Decorator Pattern</strong></a> allows us to create <em>decorators</em> to provide a flexible alternative to inheritance for extending a class.</p>
<p>In this program, I create an interface for logging messages while a program is running. I use the interface to create a <code>ConsoleLogger</code> that prints the log messages to the screen. Then I start to add decorator objects that surround, or wrap, the <code>ConsoleLogger</code>. I add decorators to attach the date, author name, and time to the log messages using the <strong>Decorator Pattern</strong>:</p>
<blockquote>
<p><a target="_blank" href="https://playbackpress.com/books/patternsbook/chapter/1/4"><strong>Decorator Pattern</strong> Logging with Decorators</a></p>
</blockquote>
<h3 id="heading-state-pattern"><strong>State Pattern</strong></h3>
<p>Sometimes there are systems that react differently based on the 'state' that they are in. A state is a period of time during which a system will react to events according to certain rules. This state-based behavior is implemented using the <a target="_blank" href="https://en.wikipedia.org/wiki/State_pattern"><strong>State Pattern</strong></a>.</p>
<p>I’ll show you how to move through the characters in a string and parse it to account for quotes within it. For example, the following string:</p>
<p><code>"hamburgers chips 'hot dogs' pickles 'french fries'"</code></p>
<p>can be split into a collection like this:</p>
<p><code>["hamburgers", "chips", "hot dogs", "pickles", "french fries"]</code></p>
<p>There are may ways to accomplish this in Java, but I’ll show a state-based approach. When a single quote is encountered within a string I will use that as an event and move between different states using the <strong>State Pattern</strong>:</p>
<blockquote>
<p><a target="_blank" href="https://playbackpress.com/books/patternsbook/chapter/1/5"><strong>State Pattern</strong> String Splitting for Search Bars</a></p>
</blockquote>
<h3 id="heading-observer-pattern"><strong>Observer Pattern</strong></h3>
<p>The <a target="_blank" href="https://en.wikipedia.org/wiki/Observer_pattern"><strong>Observer Pattern</strong></a> is used when the update of a single piece of data in one object needs to be propagated to a collection of other objects.</p>
<p>For example, when the value of a cell in a spreadsheet changes, several other cells may need to be notified of that change so that they can update themselves. Similarly, in a social network application when a user makes a post, all of their friends need to be notified so that their feeds can be updated. Both of these are essentially the same problem that the <strong>Observer Pattern</strong> solves.</p>
<p>This program creates a class to hold a time in a day called <code>MyTime</code>. Then I create two different types of <code>Observers</code> that will be notified when the time changes. The two observers will re-display the time every time it changes using the <strong>Observer Pattern</strong>:</p>
<blockquote>
<p><a target="_blank" href="https://playbackpress.com/books/patternsbook/chapter/1/6"><strong>Observer Pattern</strong> Observing the Time Change</a></p>
</blockquote>
<h3 id="heading-proxy-pattern"><strong>Proxy Pattern</strong></h3>
<p>Sometimes we design a set of objects that have a client/server relationship but later decide that the two objects should not interact directly. This program shows how to use the <a target="_blank" href="https://en.wikipedia.org/wiki/Proxy_pattern"><strong>Proxy Pattern</strong></a> to place some new functionality in between two previously cooperating classes.</p>
<p>I create a <code>Card</code> and <code>Deck</code> class for card games. The <code>Deck</code> starts out being hosted on the same machine as the <code>Driver</code>. Then I split the <code>Driver</code> and the <code>Deck</code> class so that they can be run on different machines using the <strong>Proxy Pattern</strong>:</p>
<blockquote>
<p><a target="_blank" href="https://playbackpress.com/books/patternsbook/chapter/1/7"><strong>Proxy Pattern</strong> Dealing Cards from a Remote Deck</a></p>
</blockquote>
<h3 id="heading-factory-pattern"><strong>Factory Pattern</strong></h3>
<p>The <a target="_blank" href="https://en.wikipedia.org/wiki/Factory_method_pattern"><strong>Factory Pattern</strong></a> provides a mechanism for creating 'families' of related objects without specifying their concrete classes. Instantiating concrete objects in an application makes it hard to change those objects later.</p>
<p>In this program, I will create two different families of classes for a help system for two different computing platforms using the <strong>Factory Pattern</strong>:</p>
<blockquote>
<p><a target="_blank" href="https://playbackpress.com/books/patternsbook/chapter/1/8"><strong>Factory Pattern</strong> Getting Help in Mac and Windows</a></p>
</blockquote>
<h3 id="heading-visitor-pattern"><strong>Visitor Pattern</strong></h3>
<p>The <a target="_blank" href="https://en.wikipedia.org/wiki/Visitor_pattern"><strong>Visitor Pattern</strong></a> lets you add functionality to a hierarchy of classes without changing its interface.</p>
<p>The reason why this is important is that there are times when we cannot change an existing hierarchy of classes. Perhaps I am using a hierarchy of classes that I am not in control of but I want to add some new functionality to it anyway. This is where the <strong>Visitor Pattern</strong> comes in.</p>
<p>In this program, I’ll add functionality to the <code>File</code> and <code>Directory</code> classes from the <em>Composite</em> program that I wrote earlier with minimal changes to those classes.</p>
<p>I create a <em>visitor</em> to count the number of files and directories in a topmost directory. Then I write a <em>visitor</em> to collect only the filenames in a directory including its sub-directories using the <strong>Visitor Pattern</strong>:</p>
<blockquote>
<p><a target="_blank" href="https://playbackpress.com/books/patternsbook/chapter/1/9"><strong>Visitor Pattern</strong> Adding Functionality to a Hierarchy of Classes (File and Directory)</a></p>
</blockquote>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>I hope you enjoyed learning about object-oriented design patterns. If you are interested in other programming paradigms, you can check out some of my other 'books' <a target="_blank" href="https://playbackpress.com/books">here</a>.</p>
<p>Questions and feedback are always welcome here: <a target="_blank" href="mailto:mark@playbackpress.com">mark@playbackpress.com</a></p>
<p>If you'd like to support my work and help keep Playback Press free for all, consider donating using <a target="_blank" href="https://github.com/sponsors/markm208">GitHub Sponsors</a>. I use all of the donations for hosting costs. Your support helps me continue creating educational content like this. Thank you!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is Polymorphism in Python? Explained with an Example ]]>
                </title>
                <description>
                    <![CDATA[ Polymorphism is an object-oriented programming (OOP) principle that helps you write high quality, flexible, maintainable, reusable, testable, and readable software. If you plan to work with object-oriented software, it is crucial to understand polymo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-polymorphism-in-python-example/</link>
                <guid isPermaLink="false">67a4d16ab891dd1403996d28</guid>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Object Oriented Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ oop ]]>
                    </category>
                
                    <category>
                        <![CDATA[ design patterns ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Danny ]]>
                </dc:creator>
                <pubDate>Thu, 06 Feb 2025 15:12:42 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738335631634/ef8f79a0-73df-430c-b955-a5325ca22f04.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Polymorphism is an object-oriented programming (OOP) principle that helps you write high quality, flexible, maintainable, reusable, testable, and readable software. If you plan to work with object-oriented software, it is crucial to understand polymorphism.</p>
<h2 id="heading-what-is-polymorphism">What is Polymorphism?</h2>
<p>The word <em>polymorphism</em> is derived from Greek, and means "having multiple forms":</p>
<ul>
<li><p>Poly = many</p>
</li>
<li><p>Morph = forms</p>
</li>
</ul>
<p><strong>In programming, polymorphism is the ability of an object to take many forms</strong>.</p>
<p>The key advantage of polymorphism is that it allows us to write more <strong>generic</strong> and <strong>reusable</strong> code. Instead of writing separate logic for different classes, we define common behaviours in a parent class and let child classes override them as needed. This eliminates the need for excessive <code>if-else</code> checks, making the code more maintainable and extensible.</p>
<p>MVC frameworks like <a target="_blank" href="http://djangoproject.com/">Django</a> use polymorphism to make code more flexible. For example, Django supports different databases like SQLite, MySQL, and PostgreSQL. Normally, each database requires different code to interact with it, but Django provides a single database API that works with all of them. This means you can write the same code for database operations, no matter which database you use. So, if you start a project with SQLite and later switch to PostgreSQL, you won’t need to rewrite much of your code, thanks to polymorphism.</p>
<p>In this article, to make things easy to understand, I’ll show you a bad code example with no polymorphism. We’ll discuss the issues that this bad code causes, and then solve the issues by refactoring the code to use polymorphism.</p>
<p>(Btw, if you learn better by video, checkout my <a target="_blank" href="https://youtu.be/zuPg8_qsL7A">Polymorphism in Python</a> YouTube video.)</p>
<h2 id="heading-first-an-example-with-no-polymorphism">First, an example with no polymorphism:</h2>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, brand, model, year, number_of_doors</span>):</span>
        self.brand = brand
        self.model = model
        self.year = year
        self.number_of_doors = number_of_doors

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">start</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Car is starting."</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">stop</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Car is stopping."</span>)
</code></pre>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Motorcycle</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, brand, model, year</span>):</span>
        self.brand = brand
        self.model = model
        self.year = year

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">start_bike</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Motorcycle is starting."</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">stop_bike</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Motorcycle is stopping."</span>)
</code></pre>
<p>Let’s say that we want to create a list of vehicles, then loop through it and perform an inspection on each vehicle:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Create list of vehicles to inspect</span>
vehicles = [
    Car(<span class="hljs-string">"Ford"</span>, <span class="hljs-string">"Focus"</span>, <span class="hljs-number">2008</span>, <span class="hljs-number">5</span>),
    Motorcycle(<span class="hljs-string">"Honda"</span>, <span class="hljs-string">"Scoopy"</span>, <span class="hljs-number">2018</span>),
]

<span class="hljs-comment"># Loop through list of vehicles and inspect them</span>
<span class="hljs-keyword">for</span> vehicle <span class="hljs-keyword">in</span> vehicles:
    <span class="hljs-keyword">if</span> isinstance(vehicle, Car):
        print(<span class="hljs-string">f"Inspecting <span class="hljs-subst">{vehicle.brand}</span> <span class="hljs-subst">{vehicle.model}</span> (<span class="hljs-subst">{type(vehicle).__name__}</span>)"</span>)
        vehicle.start()
        vehicle.stop()
    <span class="hljs-keyword">elif</span> isinstance(vehicle, Motorcycle):
        print(<span class="hljs-string">f"Inspecting <span class="hljs-subst">{vehicle.brand}</span> <span class="hljs-subst">{vehicle.model}</span> (<span class="hljs-subst">{type(vehicle).__name__}</span>)"</span>)
        vehicle.start_bike()
        vehicle.stop_bike()
    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">raise</span> Exception(<span class="hljs-string">"Object is not a valid vehicle"</span>)
</code></pre>
<p>Notice the ugly code inside the <code>for</code> loop! Because <code>vehicles</code> is a list of any type of object, we have to figure out what type of object we are dealing with inside each loop before we can access any information on the object.</p>
<p>This code will continue to get uglier as we add more vehicle types. For example, if we <em>extended</em> our codebase to include a new <code>Plane</code> class, then we’d need to <em>modify</em> (and potentially break) existing code – we’d have to add another conditional check in the <code>for</code> loop for planes.</p>
<h3 id="heading-introducing-polymorphism"><strong>Introducing: Polymorphism…</strong></h3>
<p>Cars and motorcycles are both vehicles. They both share some common properties and methods. So, let’s create a parent class that contains these shared properties and methods:</p>
<p>Parent class (or "superclass"):</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Vehicle</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, brand, model, year</span>):</span>
        self.brand = brand
        self.model = model
        self.year = year

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">start</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Vehicle is starting."</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">stop</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Vehicle is stopping."</span>)
</code></pre>
<p><code>Car</code> and <code>Motorcycle</code> can now <em>inherit</em> from <code>Vehicle</code>. Let’s create the child classes (or "subclasses") of the <code>Vehicle</code> superclass:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>(<span class="hljs-params">Vehicle</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, brand, model, year, number_of_doors</span>):</span>
        super().__init__(brand, model, year)
        self.number_of_doors = number_of_doors

    <span class="hljs-comment"># Below, we "override" the start and stop methods, inherited from Vehicle, to provide car-specific behaviour</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">start</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Car is starting."</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">stop</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Car is stopping."</span>)
</code></pre>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Motorcycle</span>(<span class="hljs-params">Vehicle</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, brand, model, year</span>):</span>
        super().__init__(brand, model, year)

    <span class="hljs-comment"># Below, we "override" the start and stop methods, inherited from Vehicle, to provide bike-specific behaviour</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">start</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Motorcycle is starting."</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">stop</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Motorcycle is stopping."</span>)
</code></pre>
<p><code>Car</code> and <code>Motorcycle</code> both extend <code>Vehicle</code>, as they are vehicles. But what’s the point in <code>Car</code> and <code>Motorcycle</code> both extending <code>Vehicle</code> if they are going to implement their own versions of the <code>start()</code> and <code>stop()</code> methods? Look at the code below:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Create list of vehicles to inspect</span>
vehicles = [Car(<span class="hljs-string">"Ford"</span>, <span class="hljs-string">"Focus"</span>, <span class="hljs-number">2008</span>, <span class="hljs-number">5</span>), Motorcycle(<span class="hljs-string">"Honda"</span>, <span class="hljs-string">"Scoopy"</span>, <span class="hljs-number">2018</span>)]

<span class="hljs-comment"># Loop through list of vehicles and inspect them</span>
<span class="hljs-keyword">for</span> vehicle <span class="hljs-keyword">in</span> vehicles:
    <span class="hljs-keyword">if</span> isinstance(vehicle, Vehicle):
        print(<span class="hljs-string">f"Inspecting <span class="hljs-subst">{vehicle.brand}</span> <span class="hljs-subst">{vehicle.model}</span> (<span class="hljs-subst">{type(vehicle).__name__}</span>)"</span>)
        vehicle.start()
        vehicle.stop()
    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">raise</span> Exception(<span class="hljs-string">"Object is not a valid vehicle"</span>)
</code></pre>
<p><strong>In this example</strong>:</p>
<ul>
<li><p>We have a list, <code>vehicles</code>, containing instances of both <code>Car</code> and <code>Motorcycle</code>.</p>
</li>
<li><p>We iterate through each vehicle in the list and perform a general inspection on each one.</p>
</li>
<li><p>The inspection process involves starting the vehicle, checking its brand and model, and stopping it afterwards.</p>
</li>
<li><p>Despite the vehicles being of different types, polymorphism allows us to treat them all as instances of the base <code>Vehicle</code> class. The specific implementations of the <code>start()</code> and <code>stop()</code> methods for each vehicle type are invoked dynamically at runtime, based on the actual type of each vehicle.</p>
</li>
</ul>
<p>Because the list can <em>only</em> contain objects that extend the <code>Vehicle</code> class, we know that every object will share some common fields and methods. This means that we can safely call them, without having to worry about whether each specific vehicle has these fields or methods.</p>
<p>This demonstrates how polymorphism enables code to be written in a more generic and flexible manner, allowing for easy extension and maintenance as new types of vehicles are added to the system.</p>
<p>For example, if we wanted to add another vehicle to the list, we don’t have to modify the code used to inspect vehicles (“the client code”). Instead, we can just <em>extend</em> our code base (that is, create a new class), without <em>modifying</em> existing code:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Plane</span>(<span class="hljs-params">Vehicle</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, brand, model, year, number_of_doors</span>):</span>
        super().__init__(brand, model, year)
        self.number_of_doors = number_of_doors

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">start</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Plane is starting."</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">stop</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Plane is stopping."</span>)
</code></pre>
<pre><code class="lang-python"><span class="hljs-comment"># Create list of vehicles to inspect</span>
vehicles = [
    Car(<span class="hljs-string">"Ford"</span>, <span class="hljs-string">"Focus"</span>, <span class="hljs-number">2008</span>, <span class="hljs-number">5</span>),
    Motorcycle(<span class="hljs-string">"Honda"</span>, <span class="hljs-string">"Scoopy"</span>, <span class="hljs-number">2018</span>),

    <span class="hljs-comment">########## ADD A PLANE TO THE LIST: #########</span>

    Plane(<span class="hljs-string">"Boeing"</span>, <span class="hljs-string">"747"</span>, <span class="hljs-number">2015</span>, <span class="hljs-number">16</span>),

    <span class="hljs-comment">############################################</span>
]
</code></pre>
<p>The code to perform the vehicle inspections doesn’t have to change to account for a plane. Everything still works, without having to modify our inspection logic.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Polymorphism allows clients to treat different types of objects in the same way. This greatly improves the flexibility of software and maintainability of software, as new classes can be created without you having to modify (often by adding extra <code>if</code>/<code>else if</code> blocks) existing working and tested code.</p>
<h2 id="heading-further-learning">Further Learning</h2>
<p>Polymorphism is related to many other object-oriented programming principles, such as <em>dependency injection</em> and the <em>open-closed</em> SOLID principle. If you’d like to master OOP, then check out my Udemy course:</p>
<ul>
<li><a target="_blank" href="https://www.udemy.com/course/python-oop-object-oriented-programming-from-beginner-to-pro">Python OOP: Object Oriented Programming From Beginner to Pro 🎥</a></li>
</ul>
<p>If you prefer book to video, check out my books:</p>
<ul>
<li><p><a target="_blank" href="https://www.amazon.com/dp/B0DR6ZPZQ8">Amazon Kindle and paperback 📖</a></p>
</li>
<li><p><a target="_blank" href="https://doabledanny.gumroad.com/l/python-oop-beginner-to-pro">Gumroad PDF 📖</a></p>
</li>
</ul>
<p>Thanks for reading :)</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Design Patterns in Java with Spring Boot – Explained with Code Examples ]]>
                </title>
                <description>
                    <![CDATA[ As software projects grow, it becomes increasingly important to keep your code organized, maintainable, and scalable. This is where design patterns come into play. Design patterns provide proven, reusable solutions to common software design challenge... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-design-patterns-in-java-with-spring-boot/</link>
                <guid isPermaLink="false">673616b2ea38d82d84002cda</guid>
                
                    <category>
                        <![CDATA[ Java ]]>
                    </category>
                
                    <category>
                        <![CDATA[ design patterns ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Springboot ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Birkaran Sachdev ]]>
                </dc:creator>
                <pubDate>Thu, 14 Nov 2024 15:26:42 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/1td5Iq5IvNc/upload/adaeb0229ea4ed1cd3c985d8eb92d23e.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>As software projects grow, it becomes increasingly important to keep your code organized, maintainable, and scalable. This is where design patterns come into play. Design patterns provide proven, reusable solutions to common software design challenges, making your code more efficient and easier to manage.</p>
<p>In this guide, we'll dive deep into some of the most popular design patterns and show you how to implement them in Spring Boot. By the end, you'll not only understand these patterns conceptually but also be able to apply them in your own projects with confidence.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-introduction-to-design-patterns">Introduction to Design Patterns</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-your-spring-boot-project">How to Set Up Your Spring Boot Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-the-singleton-pattern">What is the Singleton Pattern?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-the-factory-pattern">What is the Factory Pattern?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-the-strategy-pattern">What is the Strategy Pattern?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-the-observer-pattern">What is the Observer Pattern?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-spring-boots-dependency-injection">How to Use Spring Boot’s Dependency Injection</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-best-practices-and-optimization-tips">Best Practices and Optimization Tips</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion-and-key-takeaways">Conclusion and Key Takeaways</a></p>
</li>
</ul>
<h2 id="heading-introduction-to-design-patterns">Introduction to Design Patterns</h2>
<p>Design patterns are reusable solutions to common software design problems. Think of them as best practices distilled into templates that can be applied to solve specific challenges in your code. They are not specific to any language, but they can be particularly powerful in Java due to its object-oriented nature.</p>
<p>In this guide, we'll cover:</p>
<ul>
<li><p><strong>Singleton Pattern</strong>: Ensuring a class has only one instance.</p>
</li>
<li><p><strong>Factory Pattern</strong>: Creating objects without specifying the exact class.</p>
</li>
<li><p><strong>Strategy Pattern</strong>: Allowing algorithms to be selected at runtime.</p>
</li>
<li><p><strong>Observer Pattern</strong>: Setting up a publish-subscribe relationship.</p>
</li>
</ul>
<p>We'll not only cover how these patterns work but also explore how they can be applied in Spring Boot for real-world applications.</p>
<h2 id="heading-how-to-set-up-your-spring-boot-project">How to Set Up Your Spring Boot Project</h2>
<p>Before we dive into the patterns, let’s set up a Spring Boot project:</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>Make sure you have:</p>
<ul>
<li><p>Java 11+</p>
</li>
<li><p>Maven</p>
</li>
<li><p>Spring Boot CLI (optional)</p>
</li>
<li><p>Postman or curl (for testing)</p>
</li>
</ul>
<h3 id="heading-project-initialization">Project Initialization</h3>
<p>You can quickly create a Spring Boot project using Spring Initializr:</p>
<pre><code class="lang-bash">curl https://start.spring.io/starter.zip \
-d dependencies=web \
-d name=DesignPatternsDemo \
-d javaVersion=11 -o design-patterns-demo.zip
unzip design-patterns-demo.zip
<span class="hljs-built_in">cd</span> design-patterns-demo
</code></pre>
<h2 id="heading-what-is-the-singleton-pattern">What is the Singleton Pattern?</h2>
<p>The Singleton pattern ensures that a class has only one instance and provides a global access point to it. This pattern is commonly used for services like logging, configuration management, or database connections.</p>
<h3 id="heading-how-to-implement-the-singleton-pattern-in-spring-boot">How to Implement the Singleton Pattern in Spring Boot</h3>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Spring_Framework#:~:text=Creating%20and%20managing%20beans">Spring Boot beans</a> are singletons by default, meaning that Spring automatically manages the lifecycle of these beans to ensure only one instance exists. However, it's important to understand how the Singleton pattern works under the hood, especially when you're not using Spring-managed beans or need more control over instance management.</p>
<p>Let’s walk through a manual implementation of the Singleton pattern to demonstrate how you can control the creation of a single instance within your application.</p>
<h3 id="heading-step-1-create-a-loggerservice-class">Step 1: Create a <code>LoggerService</code> Class</h3>
<p>In this example, we’ll create a simple logging service using the Singleton pattern. The goal is to ensure that all parts of the application use the same logging instance.</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LoggerService</span> </span>{
    <span class="hljs-comment">// The static variable to hold the single instance</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> LoggerService instance;

    <span class="hljs-comment">// Private constructor to prevent instantiation from outside</span>
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-title">LoggerService</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// This constructor is intentionally empty to prevent other classes from creating instances</span>
    }

    <span class="hljs-comment">// Public method to provide access to the single instance</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">synchronized</span> LoggerService <span class="hljs-title">getInstance</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">if</span> (instance == <span class="hljs-keyword">null</span>) {
            instance = <span class="hljs-keyword">new</span> LoggerService();
        }
        <span class="hljs-keyword">return</span> instance;
    }

    <span class="hljs-comment">// Example logging method</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">log</span><span class="hljs-params">(String message)</span> </span>{
        System.out.println(<span class="hljs-string">"[LOG] "</span> + message);
    }
}
</code></pre>
<ul>
<li><p><strong>Static Variable</strong> (<code>instance</code>): This holds the single instance of <code>LoggerService</code>.</p>
</li>
<li><p><strong>Private Constructor</strong>: The constructor is marked private to prevent other classes from creating new instances directly.</p>
</li>
<li><p><strong>Synchronized</strong> <code>getInstance()</code> Method: The method is synchronized to make it thread-safe, ensuring that only one instance is created even if multiple threads try to access it simultaneously.</p>
</li>
<li><p><strong>Lazy Initialization</strong>: The instance is created only when it's first requested (<code>lazy initialization</code>), which is efficient in terms of memory usage.</p>
</li>
</ul>
<p><strong>Real-World Usage</strong>: This pattern is commonly used for shared resources, such as logging, configuration settings, or managing database connections, where you want to control access and ensure that only one instance is used throughout your application.</p>
<h3 id="heading-step-2-use-the-singleton-in-a-spring-boot-controller">Step 2: Use the Singleton in a Spring Boot Controller</h3>
<p>Now, let's see how we can use our <code>LoggerService</code> Singleton within a Spring Boot controller. This controller will expose an endpoint that logs a message whenever it's accessed.</p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> org.springframework.http.ResponseEntity;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.GetMapping;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RestController;

<span class="hljs-meta">@RestController</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LogController</span> </span>{

    <span class="hljs-meta">@GetMapping("/log")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> ResponseEntity&lt;String&gt; <span class="hljs-title">logMessage</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// Accessing the Singleton instance of LoggerService</span>
        LoggerService logger = LoggerService.getInstance();
        logger.log(<span class="hljs-string">"This is a log message!"</span>);
        <span class="hljs-keyword">return</span> ResponseEntity.ok(<span class="hljs-string">"Message logged successfully"</span>);
    }
}
</code></pre>
<ul>
<li><p><strong>GET Endpoint</strong>: We’ve created a <code>/log</code> endpoint that, when accessed, logs a message using the <code>LoggerService</code>.</p>
</li>
<li><p><strong>Singleton Usage</strong>: Instead of creating a new instance of <code>LoggerService</code>, we call <code>getInstance()</code> to ensure we’re using the same instance every time.</p>
</li>
<li><p><strong>Response</strong>: After logging, the endpoint returns a response indicating success.</p>
</li>
</ul>
<h3 id="heading-step-3-testing-the-singleton-pattern">Step 3: Testing the Singleton Pattern</h3>
<p>Now, let's test this endpoint using Postman or your browser:</p>
<pre><code class="lang-bash">GET http://localhost:8080/<span class="hljs-built_in">log</span>
</code></pre>
<p><strong>Expected Output</strong>:</p>
<ul>
<li><p>Console log: <code>[LOG] This is a log message!</code></p>
</li>
<li><p>HTTP Response: <code>Message logged successfully</code></p>
</li>
</ul>
<p>You can call the endpoint multiple times, and you'll see that the same instance of <code>LoggerService</code> is used, as indicated by the consistent log output.</p>
<h3 id="heading-real-world-use-cases-for-the-singleton-pattern">Real-World Use Cases for the Singleton Pattern</h3>
<p>Here’s when you might want to use the Singleton pattern in real-world applications:</p>
<ol>
<li><p><strong>Configuration Management</strong>: Ensure that your application uses a consistent set of configuration settings, especially when those settings are loaded from files or databases.</p>
</li>
<li><p><strong>Database Connection Pools</strong>: Control access to a limited number of database connections, ensuring that the same pool is shared across the application.</p>
</li>
<li><p><strong>Caching</strong>: Maintain a single cache instance to avoid inconsistent data.</p>
</li>
<li><p><strong>Logging Services</strong>: As shown in this example, use a single logging service to centralize log outputs across different modules of your application.</p>
</li>
</ol>
<h3 id="heading-key-takeaways">Key Takeaways</h3>
<ul>
<li><p>The Singleton pattern is an easy way to ensure that only one instance of a class is created.</p>
</li>
<li><p>Thread safety is crucial if multiple threads are accessing the Singleton, which is why we used <code>synchronized</code> in our example.</p>
</li>
<li><p>Spring Boot beans are already singletons by default, but understanding how to implement it manually helps you gain more control when needed.</p>
</li>
</ul>
<p>This covers the implementation and usage of the Singleton pattern. Next, we’ll explore the Factory pattern to see how it can help streamline object creation.</p>
<h2 id="heading-what-is-the-factory-pattern">What is the Factory Pattern?</h2>
<p>The Factory pattern allows you to create objects without specifying the exact class. This pattern is useful when you have different types of objects that need to be instantiated based on some input.</p>
<h3 id="heading-how-to-implementing-a-factory-in-spring-boot">How to Implementing a Factory in Spring Boot</h3>
<p>The Factory pattern is incredibly useful when you need to create objects based on certain criteria but want to decouple the object creation process from your main application logic.</p>
<p>In this section, we’ll walk through building a <code>NotificationFactory</code> to send notifications via Email or SMS. This is especially useful if you anticipate adding more notification types in the future, such as push notifications or in-app alerts, without changing your existing code.</p>
<h3 id="heading-step-1-create-the-notification-interface">Step 1: Create the <code>Notification</code> Interface</h3>
<p>The first step is to define a common interface that all notification types will implement. This ensures that each type of notification (Email, SMS, and so on) will have a consistent <code>send()</code> method.</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Notification</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">send</span><span class="hljs-params">(String message)</span></span>;
}
</code></pre>
<ul>
<li><p><strong>Purpose</strong>: The <code>Notification</code> interface defines the contract for sending notifications. Any class that implements this interface must provide an implementation for the <code>send()</code> method.</p>
</li>
<li><p><strong>Scalability</strong>: By using an interface, you can easily extend your application in the future to include other types of notifications without modifying existing code.</p>
</li>
</ul>
<h3 id="heading-step-2-implement-emailnotification-and-smsnotification">Step 2: Implement <code>EmailNotification</code> and <code>SMSNotification</code></h3>
<p>Now, let's implement two concrete classes, one for sending emails and another for sending SMS messages.</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EmailNotification</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Notification</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">send</span><span class="hljs-params">(String message)</span> </span>{
        System.out.println(<span class="hljs-string">"Sending Email: "</span> + message);
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SMSNotification</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Notification</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">send</span><span class="hljs-params">(String message)</span> </span>{
        System.out.println(<span class="hljs-string">"Sending SMS: "</span> + message);
    }
}
</code></pre>
<h3 id="heading-step-3-create-a-notificationfactory">Step 3: Create a <code>NotificationFactory</code></h3>
<p>The <code>NotificationFactory</code> class is responsible for creating instances of <code>Notification</code> based on the specified type. This design ensures that the <code>NotificationController</code> doesn’t need to know about the details of object creation.</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NotificationFactory</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Notification <span class="hljs-title">createNotification</span><span class="hljs-params">(String type)</span> </span>{
        <span class="hljs-keyword">switch</span> (type.toUpperCase()) {
            <span class="hljs-keyword">case</span> <span class="hljs-string">"EMAIL"</span>:
                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> EmailNotification();
            <span class="hljs-keyword">case</span> <span class="hljs-string">"SMS"</span>:
                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> SMSNotification();
            <span class="hljs-keyword">default</span>:
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalArgumentException(<span class="hljs-string">"Unknown notification type: "</span> + type);
        }
    }
}
</code></pre>
<p><strong>Factory Method</strong> (<code>createNotification()</code>):</p>
<ul>
<li><p>The factory method takes a string (<code>type</code>) as input and returns an instance of the corresponding notification class.</p>
</li>
<li><p><strong>Switch Statement</strong>: The switch statement selects the appropriate notification type based on the input.</p>
</li>
<li><p><strong>Error Handling</strong>: If the provided type is not recognized, it throws an <code>IllegalArgumentException</code>. This ensures that invalid types are caught early.</p>
</li>
</ul>
<p><strong>Why Use a Factory?</strong></p>
<ul>
<li><p><strong>Decoupling</strong>: The factory pattern decouples object creation from the business logic. This makes your code more modular and easier to maintain.</p>
</li>
<li><p><strong>Extensibility</strong>: If you want to add a new notification type, you only need to update the factory without changing the controller logic.</p>
</li>
</ul>
<h3 id="heading-step-4-use-the-factory-in-a-spring-boot-controller">Step 4: Use the Factory in a Spring Boot Controller</h3>
<p>Now, let’s put everything together by creating a Spring Boot controller that uses the <code>NotificationFactory</code> to send notifications based on the user’s request.</p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> org.springframework.http.ResponseEntity;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.GetMapping;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RequestParam;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RestController;

<span class="hljs-meta">@RestController</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NotificationController</span> </span>{

    <span class="hljs-meta">@GetMapping("/notify")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> ResponseEntity&lt;String&gt; <span class="hljs-title">notify</span><span class="hljs-params">(<span class="hljs-meta">@RequestParam</span> String type, <span class="hljs-meta">@RequestParam</span> String message)</span> </span>{
        <span class="hljs-keyword">try</span> {
            <span class="hljs-comment">// Create the appropriate Notification object using the factory</span>
            Notification notification = NotificationFactory.createNotification(type);
            notification.send(message);
            <span class="hljs-keyword">return</span> ResponseEntity.ok(<span class="hljs-string">"Notification sent successfully!"</span>);
        } <span class="hljs-keyword">catch</span> (IllegalArgumentException e) {
            <span class="hljs-keyword">return</span> ResponseEntity.badRequest().body(e.getMessage());
        }
    }
}
</code></pre>
<p><strong>GET Endpoint</strong> (<code>/notify</code>):</p>
<ul>
<li><p>The controller exposes a <code>/notify</code> endpoint that accepts two query parameters: <code>type</code> (either "EMAIL" or "SMS") and <code>message</code>.</p>
</li>
<li><p>It uses the <code>NotificationFactory</code> to create the appropriate notification type and sends the message.</p>
</li>
<li><p><strong>Error Handling</strong>: If an invalid notification type is provided, the controller catches the <code>IllegalArgumentException</code> and returns a <code>400 Bad Request</code> response.</p>
</li>
</ul>
<h3 id="heading-step-5-testing-the-factory-pattern">Step 5: Testing the Factory Pattern</h3>
<p>Let’s test the endpoint using Postman or a browser:</p>
<ol>
<li><p><strong>Send an Email Notification</strong>:</p>
<pre><code class="lang-bash"> GET http://localhost:8080/notify?<span class="hljs-built_in">type</span>=email&amp;message=Hello%20Email
</code></pre>
<p> <strong>Output</strong>:</p>
<pre><code class="lang-bash"> Sending Email: Hello Email
</code></pre>
</li>
<li><p><strong>Send an SMS Notification</strong>:</p>
<pre><code class="lang-bash"> GET http://localhost:8080/notify?<span class="hljs-built_in">type</span>=sms&amp;message=Hello%20SMS
</code></pre>
<p> <strong>Output</strong>:</p>
<pre><code class="lang-bash"> Sending SMS: Hello SMS
</code></pre>
</li>
<li><p><strong>Test with an Invalid Type</strong>:</p>
<pre><code class="lang-bash"> GET http://localhost:8080/notify?<span class="hljs-built_in">type</span>=unknown&amp;message=Test
</code></pre>
<p> <strong>Output</strong>:</p>
<pre><code class="lang-bash"> Bad Request: Unknown notification <span class="hljs-built_in">type</span>: unknown
</code></pre>
</li>
</ol>
<h3 id="heading-real-world-use-cases-for-the-factory-pattern">Real-World Use Cases for the Factory Pattern</h3>
<p>The Factory pattern is particularly useful in scenarios where:</p>
<ol>
<li><p><strong>Dynamic Object Creation</strong>: When you need to create objects based on user input, like sending different types of notifications, generating reports in various formats, or handling different payment methods.</p>
</li>
<li><p><strong>Decoupling Object Creation</strong>: By using a factory, you can keep your main business logic separate from object creation, making your code more maintainable.</p>
</li>
<li><p><strong>Scalability</strong>: Easily extend your application to support new types of notifications without modifying existing code. Simply add a new class that implements the <code>Notification</code> interface and update the factory.</p>
</li>
</ol>
<h2 id="heading-what-is-the-strategy-pattern">What is the Strategy Pattern?</h2>
<p>The Strategy pattern is perfect when you need to switch between multiple algorithms or behaviors dynamically. It allows you to define a family of algorithms, encapsulate each one within separate classes, and make them easily interchangeable at runtime. This is especially useful for selecting an algorithm based on specific conditions, keeping your code clean, modular, and flexible.</p>
<p><strong>Real-World Use Case</strong>: Imagine an e-commerce system that needs to support multiple payment options, like credit cards, PayPal, or bank transfers. By using the Strategy pattern, you can easily add or modify payment methods without altering existing code. This approach ensures that your application remains scalable and maintainable as you introduce new features or update existing ones.</p>
<p>We’ll demonstrate this pattern with a Spring Boot example that handles payments using either a credit card or PayPal strategy.</p>
<h3 id="heading-step-1-define-a-paymentstrategy-interface">Step 1: Define a <code>PaymentStrategy</code> Interface</h3>
<p>We start by creating a common interface that all payment strategies will implement:</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">PaymentStrategy</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">pay</span><span class="hljs-params">(<span class="hljs-keyword">double</span> amount)</span></span>;
}
</code></pre>
<p>The interface defines a contract for all payment methods, ensuring consistency across implementations.</p>
<h3 id="heading-step-2-implement-payment-strategies">Step 2: Implement Payment Strategies</h3>
<p>Create concrete classes for credit card and PayPal payments.</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CreditCardPayment</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">PaymentStrategy</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">pay</span><span class="hljs-params">(<span class="hljs-keyword">double</span> amount)</span> </span>{
        System.out.println(<span class="hljs-string">"Paid $"</span> + amount + <span class="hljs-string">" with Credit Card"</span>);
    }
}

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PayPalPayment</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">PaymentStrategy</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">pay</span><span class="hljs-params">(<span class="hljs-keyword">double</span> amount)</span> </span>{
        System.out.println(<span class="hljs-string">"Paid $"</span> + amount + <span class="hljs-string">" via PayPal"</span>);
    }
}
</code></pre>
<p>Each class implements the <code>pay()</code> method with its specific behavior.</p>
<h3 id="heading-step-3-use-the-strategy-in-a-controller">Step 3: Use the Strategy in a Controller</h3>
<p>Create a controller to dynamically select a payment strategy based on user input:</p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> org.springframework.http.ResponseEntity;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.GetMapping;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RequestParam;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RestController;

<span class="hljs-meta">@RestController</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PaymentController</span> </span>{

    <span class="hljs-meta">@GetMapping("/pay")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> ResponseEntity&lt;String&gt; <span class="hljs-title">processPayment</span><span class="hljs-params">(<span class="hljs-meta">@RequestParam</span> String method, <span class="hljs-meta">@RequestParam</span> <span class="hljs-keyword">double</span> amount)</span> </span>{
        PaymentStrategy strategy = selectPaymentStrategy(method);
        <span class="hljs-keyword">if</span> (strategy == <span class="hljs-keyword">null</span>) {
            <span class="hljs-keyword">return</span> ResponseEntity.badRequest().body(<span class="hljs-string">"Invalid payment method"</span>);
        }
        strategy.pay(amount);
        <span class="hljs-keyword">return</span> ResponseEntity.ok(<span class="hljs-string">"Payment processed successfully!"</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> PaymentStrategy <span class="hljs-title">selectPaymentStrategy</span><span class="hljs-params">(String method)</span> </span>{
        <span class="hljs-keyword">switch</span> (method.toUpperCase()) {
            <span class="hljs-keyword">case</span> <span class="hljs-string">"CREDIT"</span>: <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> CreditCardPayment();
            <span class="hljs-keyword">case</span> <span class="hljs-string">"PAYPAL"</span>: <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> PayPalPayment();
            <span class="hljs-keyword">default</span>: <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
        }
    }
}
</code></pre>
<p>The endpoint accepts <code>method</code> and <code>amount</code> as query parameters and processes the payment using the appropriate strategy.</p>
<h3 id="heading-step-4-testing-the-endpoint">Step 4: Testing the Endpoint</h3>
<ol>
<li><p><strong>Credit Card Payment</strong>:</p>
<pre><code class="lang-bash"> GET http://localhost:8080/pay?method=credit&amp;amount=100
</code></pre>
<p> Output: <code>Paid $100.0 with Credit Card</code></p>
</li>
<li><p><strong>PayPal Payment</strong>:</p>
<pre><code class="lang-bash"> GET http://localhost:8080/pay?method=paypal&amp;amount=50
</code></pre>
<p> Output: <code>Paid $50.0 via PayPal</code></p>
</li>
<li><p><strong>Invalid Method</strong>:</p>
<pre><code class="lang-bash"> GET http://localhost:8080/pay?method=bitcoin&amp;amount=25
</code></pre>
<p> Output: <code>Invalid payment method</code></p>
</li>
</ol>
<h3 id="heading-use-cases-for-the-strategy-pattern">Use Cases for the Strategy Pattern</h3>
<ul>
<li><p><strong>Payment Processing</strong>: Dynamically switch between different payment gateways.</p>
</li>
<li><p><strong>Sorting Algorithms</strong>: Choose the best sorting method based on data size.</p>
</li>
<li><p><strong>File Exporting</strong>: Export reports in various formats (PDF, Excel, CSV).</p>
</li>
</ul>
<h3 id="heading-key-takeaways-1">Key Takeaways</h3>
<ul>
<li><p>The Strategy pattern keeps your code modular and follows the Open/Closed principle.</p>
</li>
<li><p>Adding new strategies is easy—just create a new class implementing the <code>PaymentStrategy</code> interface.</p>
</li>
<li><p>It’s ideal for scenarios where you need flexible algorithm selection at runtime.</p>
</li>
</ul>
<p>Next, we’ll explore the Observer pattern, perfect for handling event-driven architectures.</p>
<h2 id="heading-what-is-the-observer-pattern">What is the Observer Pattern?</h2>
<p>The Observer pattern is ideal when you have one object (the subject) that needs to notify multiple other objects (observers) about changes in its state. It’s perfect for event-driven systems where updates need to be pushed to various components without creating tight coupling between them. This pattern allows you to maintain a clean architecture, especially when different parts of your system need to react to changes independently.</p>
<p><strong>Real-World Use Case</strong>: This pattern is commonly used in systems that send notifications or alerts, such as chat applications or stock price trackers, where updates need to be pushed to users in real-time. By using the Observer pattern, you can add or remove notification types easily without altering the core logic.</p>
<p>We’ll demonstrate how to implement this pattern in Spring Boot by building a simple notification system where both Email and SMS notifications are sent whenever a user registers.</p>
<h3 id="heading-step-1-create-an-observer-interface">Step 1: Create an <code>Observer</code> Interface</h3>
<p>We begin by defining a common interface that all observers will implement:</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Observer</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">update</span><span class="hljs-params">(String event)</span></span>;
}
</code></pre>
<p>The interface establishes a contract where all observers must implement the <code>update()</code> method, which will be triggered whenever the subject changes.</p>
<h3 id="heading-step-2-implement-emailobserver-and-smsobserver">Step 2: Implement <code>EmailObserver</code> and <code>SMSObserver</code></h3>
<p>Next, we create two concrete implementations of the <code>Observer</code> interface to handle email and SMS notifications.</p>
<h4 id="heading-emailobserver-class"><code>EmailObserver</code> Class</h4>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EmailObserver</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Observer</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">update</span><span class="hljs-params">(String event)</span> </span>{
        System.out.println(<span class="hljs-string">"Email sent for event: "</span> + event);
    }
}
</code></pre>
<p>The <code>EmailObserver</code> handles sending email notifications whenever it's notified of an event.</p>
<h4 id="heading-smsobserver-class"><code>SMSObserver</code> Class</h4>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SMSObserver</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Observer</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">update</span><span class="hljs-params">(String event)</span> </span>{
        System.out.println(<span class="hljs-string">"SMS sent for event: "</span> + event);
    }
}
</code></pre>
<p>The <code>SMSObserver</code> handles sending SMS notifications whenever it's notified.</p>
<h3 id="heading-step-3-create-a-userservice-class-the-subject">Step 3: Create a <code>UserService</code> Class (The Subject)</h3>
<p>We’ll now create a <code>UserService</code> class that acts as the subject, notifying its registered observers whenever a user registers.</p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> org.springframework.stereotype.Service;
<span class="hljs-keyword">import</span> java.util.ArrayList;
<span class="hljs-keyword">import</span> java.util.List;

<span class="hljs-meta">@Service</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserService</span> </span>{
    <span class="hljs-keyword">private</span> List&lt;Observer&gt; observers = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;();

    <span class="hljs-comment">// Method to register observers</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">registerObserver</span><span class="hljs-params">(Observer observer)</span> </span>{
        observers.add(observer);
    }

    <span class="hljs-comment">// Method to notify all registered observers of an event</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">notifyObservers</span><span class="hljs-params">(String event)</span> </span>{
        <span class="hljs-keyword">for</span> (Observer observer : observers) {
            observer.update(event);
        }
    }

    <span class="hljs-comment">// Method to register a new user and notify observers</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">registerUser</span><span class="hljs-params">(String username)</span> </span>{
        System.out.println(<span class="hljs-string">"User registered: "</span> + username);
        notifyObservers(<span class="hljs-string">"User Registration"</span>);
    }
}
</code></pre>
<ul>
<li><p><strong>Observers List</strong>: Keeps track of all registered observers.</p>
</li>
<li><p><code>registerObserver()</code> Method: Adds new observers to the list.</p>
</li>
<li><p><code>notifyObservers()</code> Method: Notifies all registered observers when an event occurs.</p>
</li>
<li><p><code>registerUser()</code> Method: Registers a new user and triggers notifications to all observers.</p>
</li>
</ul>
<h3 id="heading-step-4-use-the-observer-pattern-in-a-controller">Step 4: Use the Observer Pattern in a Controller</h3>
<p>Finally, we’ll create a Spring Boot controller to expose an endpoint for user registration. This controller will register both <code>EmailObserver</code> and <code>SMSObserver</code> with the <code>UserService</code>.</p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> org.springframework.http.ResponseEntity;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.*;

<span class="hljs-meta">@RestController</span>
<span class="hljs-meta">@RequestMapping("/api")</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserController</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> UserService userService;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">UserController</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">this</span>.userService = <span class="hljs-keyword">new</span> UserService();
        <span class="hljs-comment">// Register observers</span>
        userService.registerObserver(<span class="hljs-keyword">new</span> EmailObserver());
        userService.registerObserver(<span class="hljs-keyword">new</span> SMSObserver());
    }

    <span class="hljs-meta">@PostMapping("/register")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> ResponseEntity&lt;String&gt; <span class="hljs-title">registerUser</span><span class="hljs-params">(<span class="hljs-meta">@RequestParam</span> String username)</span> </span>{
        userService.registerUser(username);
        <span class="hljs-keyword">return</span> ResponseEntity.ok(<span class="hljs-string">"User registered and notifications sent!"</span>);
    }
}
</code></pre>
<ul>
<li><p><strong>Endpoint</strong> (<code>/register</code>): Accepts a <code>username</code> parameter and registers the user, triggering notifications to all observers.</p>
</li>
<li><p><strong>Observers</strong>: Both <code>EmailObserver</code> and <code>SMSObserver</code> are registered with <code>UserService</code>, so they are notified whenever a user registers.</p>
</li>
</ul>
<h3 id="heading-testing-the-observer-pattern">Testing the Observer Pattern</h3>
<p>Now, let’s test our implementation using Postman or a browser:</p>
<pre><code class="lang-bash">POST http://localhost:8080/api/register?username=JohnDoe
</code></pre>
<p><strong>Expected Output in Console</strong>:</p>
<pre><code class="lang-java">User registered: JohnDoe
Email sent <span class="hljs-keyword">for</span> event: User Registration
SMS sent <span class="hljs-keyword">for</span> event: User Registration
</code></pre>
<p>The system registers the user and notifies both the Email and SMS observers, showcasing the flexibility of the Observer pattern.</p>
<h3 id="heading-real-world-applications-of-the-observer-pattern">Real-World Applications of the Observer Pattern</h3>
<ol>
<li><p><strong>Notification Systems</strong>: Sending updates to users via different channels (email, SMS, push notifications) when certain events occur.</p>
</li>
<li><p><strong>Event-Driven Architectures</strong>: Notifying multiple subsystems when specific actions take place, such as user activities or system alerts.</p>
</li>
<li><p><strong>Data Streaming</strong>: Broadcasting data changes to various consumers in real-time (for example, live stock prices or social media feeds).</p>
</li>
</ol>
<h2 id="heading-how-to-use-spring-boots-dependency-injection">How to Use Spring Boot’s Dependency Injection</h2>
<p>So far, we’ve been manually creating objects to demonstrate design patterns. However, in real-world Spring Boot applications, Dependency Injection (DI) is the preferred way to manage object creation. DI allows Spring to automatically handle the instantiation and wiring of your classes, making your code more modular, testable, and maintainable.</p>
<p>Let’s refactor our Strategy pattern example to take advantage of Spring Boot's powerful DI capabilities. This will allow us to switch between payment strategies dynamically, using Spring’s annotations to manage dependencies.</p>
<h3 id="heading-updated-strategy-pattern-using-spring-boots-di">Updated Strategy Pattern Using Spring Boot's DI</h3>
<p>In our refactored example, we’ll leverage Spring’s annotations like <code>@Component</code>, <code>@Service</code>, and <code>@Autowired</code> to streamline the process of injecting dependencies.</p>
<h4 id="heading-step-1-annotate-payment-strategies-with-component">Step 1: Annotate Payment Strategies with <code>@Component</code></h4>
<p>First, we’ll mark our strategy implementations with the <code>@Component</code> annotation so that Spring can detect and manage them automatically.</p>
<pre><code class="lang-java"><span class="hljs-meta">@Component("creditCardPayment")</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CreditCardPayment</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">PaymentStrategy</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">pay</span><span class="hljs-params">(<span class="hljs-keyword">double</span> amount)</span> </span>{
        System.out.println(<span class="hljs-string">"Paid $"</span> + amount + <span class="hljs-string">" with Credit Card"</span>);
    }
}

<span class="hljs-meta">@Component("payPalPayment")</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PayPalPayment</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">PaymentStrategy</span> </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">pay</span><span class="hljs-params">(<span class="hljs-keyword">double</span> amount)</span> </span>{
        System.out.println(<span class="hljs-string">"Paid $"</span> + amount + <span class="hljs-string">" using PayPal"</span>);
    }
}
</code></pre>
<ul>
<li><p><code>@Component</code> Annotation: By adding <code>@Component</code>, we tell Spring to treat these classes as Spring-managed beans. The string value (<code>"creditCardPayment"</code> and <code>"payPalPayment"</code>) acts as the bean identifier.</p>
</li>
<li><p><strong>Flexibility</strong>: This setup allows us to switch between strategies by using the appropriate bean identifier.</p>
</li>
</ul>
<h4 id="heading-step-2-refactor-the-paymentservice-to-use-dependency-injection">Step 2: Refactor the <code>PaymentService</code> to Use Dependency Injection</h4>
<p>Next, let’s modify the <code>PaymentService</code> to inject a specific payment strategy using <code>@Autowired</code> and <code>@Qualifier</code>.</p>
<pre><code class="lang-java"><span class="hljs-meta">@Service</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PaymentService</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> PaymentStrategy paymentStrategy;

    <span class="hljs-meta">@Autowired</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">PaymentService</span><span class="hljs-params">(<span class="hljs-meta">@Qualifier("payPalPayment")</span> PaymentStrategy paymentStrategy)</span> </span>{
        <span class="hljs-keyword">this</span>.paymentStrategy = paymentStrategy;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">processPayment</span><span class="hljs-params">(<span class="hljs-keyword">double</span> amount)</span> </span>{
        paymentStrategy.pay(amount);
    }
}
</code></pre>
<ul>
<li><p><code>@Service</code> Annotation: Marks <code>PaymentService</code> as a Spring-managed service bean.</p>
</li>
<li><p><code>@Autowired</code>: Spring injects the required dependency automatically.</p>
</li>
<li><p><code>@Qualifier</code>: Specifies which implementation of <code>PaymentStrategy</code> to inject. In this example, we’re using <code>"payPalPayment"</code>.</p>
</li>
<li><p><strong>Ease of Configuration</strong>: By simply changing the <code>@Qualifier</code> value, you can switch the payment strategy without altering any business logic.</p>
</li>
</ul>
<h3 id="heading-step-3-using-the-refactored-service-in-a-controller">Step 3: Using the Refactored Service in a Controller</h3>
<p>To see the benefits of this refactoring, let’s update the controller to use our <code>PaymentService</code>:</p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.*;

<span class="hljs-meta">@RestController</span>
<span class="hljs-meta">@RequestMapping("/api")</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PaymentController</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> PaymentService paymentService;

    <span class="hljs-meta">@Autowired</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">PaymentController</span><span class="hljs-params">(PaymentService paymentService)</span> </span>{
        <span class="hljs-keyword">this</span>.paymentService = paymentService;
    }

    <span class="hljs-meta">@GetMapping("/pay")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">makePayment</span><span class="hljs-params">(<span class="hljs-meta">@RequestParam</span> <span class="hljs-keyword">double</span> amount)</span> </span>{
        paymentService.processPayment(amount);
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Payment processed using the current strategy!"</span>;
    }
}
</code></pre>
<ul>
<li><p><code>@Autowired</code>: The controller automatically receives the <code>PaymentService</code> with the injected payment strategy.</p>
</li>
<li><p><strong>GET Endpoint (</strong><code>/pay</code>): When accessed, it processes a payment using the currently configured strategy (PayPal in this example).</p>
</li>
</ul>
<h3 id="heading-testing-the-refactored-strategy-pattern-with-di">Testing the Refactored Strategy Pattern with DI</h3>
<p>Now, let’s test the new implementation using Postman or a browser:</p>
<pre><code class="lang-bash">GET http://localhost:8080/api/pay?amount=100
</code></pre>
<p><strong>Expected Output</strong>:</p>
<pre><code class="lang-bash">Paid <span class="hljs-variable">$100</span>.0 using PayPal
</code></pre>
<p>If you change the qualifier in <code>PaymentService</code> to <code>"creditCardPayment"</code>, the output will change accordingly:</p>
<pre><code class="lang-bash">Paid <span class="hljs-variable">$100</span>.0 with Credit Card
</code></pre>
<h3 id="heading-benefits-of-using-dependency-injection">Benefits of Using Dependency Injection</h3>
<ul>
<li><p><strong>Loose Coupling</strong>: The service and controller don’t need to know the details of how a payment is processed. They simply rely on Spring to inject the correct implementation.</p>
</li>
<li><p><strong>Modularity</strong>: You can easily add new payment methods (for example, <code>BankTransferPayment</code>, <code>CryptoPayment</code>) by creating new classes annotated with <code>@Component</code> and adjusting the <code>@Qualifier</code>.</p>
</li>
<li><p><strong>Configurability</strong>: By leveraging Spring Profiles, you can switch strategies based on the environment (for example, development vs. production).</p>
</li>
</ul>
<p><strong>Example</strong>: You can use <code>@Profile</code> to automatically inject different strategies based on the active profile:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Component</span>
<span class="hljs-meta">@Profile("dev")</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DevPaymentStrategy</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">PaymentStrategy</span> </span>{ <span class="hljs-comment">/* ... */</span> }

<span class="hljs-meta">@Component</span>
<span class="hljs-meta">@Profile("prod")</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProdPaymentStrategy</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">PaymentStrategy</span> </span>{ <span class="hljs-comment">/* ... */</span> }
</code></pre>
<h3 id="heading-key-takeaways-2">Key Takeaways</h3>
<ul>
<li><p>By using Spring Boot’s DI, you can simplify object creation and improve the flexibility of your code.</p>
</li>
<li><p>The Strategy Pattern combined with DI allows you to easily switch between different strategies without changing your core business logic.</p>
</li>
<li><p>Using <code>@Qualifier</code> and Spring Profiles gives you the flexibility to configure your application based on different environments or requirements.</p>
</li>
</ul>
<p>This approach not only makes your code cleaner but also prepares it for more advanced configurations and scaling in the future. In the next section, we’ll explore Best Practices and Optimization Tips to take your Spring Boot applications to the next level.</p>
<h2 id="heading-best-practices-and-optimization-tips">Best Practices and Optimization Tips</h2>
<h3 id="heading-general-best-practices">General Best Practices</h3>
<ul>
<li><p><strong>Don’t overuse patterns</strong>: Use them only when necessary. Overengineering can make your code harder to maintain.</p>
</li>
<li><p><strong>Favor composition over inheritance</strong>: Patterns like Strategy and Observer are great examples of this principle.</p>
</li>
<li><p><strong>Keep your patterns flexible</strong>: Leverage interfaces to keep your code decoupled.</p>
</li>
</ul>
<h3 id="heading-performance-considerations">Performance Considerations</h3>
<ul>
<li><p><strong>Singleton Pattern</strong>: Ensure thread safety by using <code>synchronized</code> or the <code>Bill Pugh Singleton Design</code>.</p>
</li>
<li><p><strong>Factory Pattern</strong>: Cache objects if they are expensive to create.</p>
</li>
<li><p><strong>Observer Pattern</strong>: Use asynchronous processing if you have many observers to prevent blocking.</p>
</li>
</ul>
<h3 id="heading-advanced-topics">Advanced Topics</h3>
<ul>
<li><p>Using <strong>Reflection</strong> with the Factory pattern for dynamic class loading.</p>
</li>
<li><p>Leveraging <strong>Spring Profiles</strong> to switch strategies based on the environment.</p>
</li>
<li><p>Adding <strong>Swagger Documentation</strong> for your API endpoints.</p>
</li>
</ul>
<h2 id="heading-conclusion-and-key-takeaways">Conclusion and Key Takeaways</h2>
<p>In this tutorial, we explored some of the most powerful design patterns—Singleton, Factory, Strategy, and Observer—and demonstrated how to implement them in Spring Boot. Let’s briefly summarize each pattern and highlight what it’s best suited for:</p>
<p><strong>Singleton Pattern</strong>:</p>
<ul>
<li><p><strong>Summary</strong>: Ensures that a class has only one instance and provides a global access point to it.</p>
</li>
<li><p><strong>Best For</strong>: Managing shared resources like configuration settings, database connections, or logging services. It’s ideal when you want to control access to a shared instance across your entire application.</p>
</li>
</ul>
<p><strong>Factory Pattern</strong>:</p>
<ul>
<li><p><strong>Summary</strong>: Provides a way to create objects without specifying the exact class to be instantiated. This pattern decouples object creation from the business logic.</p>
</li>
<li><p><strong>Best For</strong>: Scenarios where you need to create different types of objects based on input conditions, such as sending notifications via email, SMS, or push notifications. It’s great for making your code more modular and extensible.</p>
</li>
</ul>
<p><strong>Strategy Pattern</strong>:</p>
<ul>
<li><p><strong>Summary</strong>: Allows you to define a family of algorithms, encapsulate each one, and make them interchangeable. This pattern helps you choose an algorithm at runtime.</p>
</li>
<li><p><strong>Best For</strong>: When you need to switch between different behaviors or algorithms dynamically, such as processing various payment methods in an e-commerce application. It keeps your code flexible and adheres to the Open/Closed Principle.</p>
</li>
</ul>
<p><strong>Observer Pattern</strong>:</p>
<ul>
<li><p><strong>Summary</strong>: Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified automatically.</p>
</li>
<li><p><strong>Best For</strong>: Event-driven systems like notification services, real-time updates in chat apps, or systems that need to react to changes in data. It’s ideal for decoupling components and making your system more scalable.</p>
</li>
</ul>
<h3 id="heading-whats-next">What’s Next?</h3>
<p>Now that you’ve learned these essential design patterns, try integrating them into your existing projects to see how they can improve your code structure and scalability. Here are a few suggestions for further exploration:</p>
<ul>
<li><p><strong>Experiment</strong>: Try implementing other design patterns like <strong>Decorator</strong>, <strong>Proxy</strong>, and <strong>Builder</strong> to expand your toolkit.</p>
</li>
<li><p><strong>Practice</strong>: Use these patterns to refactor existing projects and enhance their maintainability.</p>
</li>
<li><p><strong>Share</strong>: If you have any questions or want to share your experience, feel free to reach out!</p>
</li>
</ul>
<p>I hope this guide has helped you understand how to effectively use design patterns in Java. Keep experimenting, and happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What are the SOLID Principles in C#? Explained With Code Examples ]]>
                </title>
                <description>
                    <![CDATA[ The SOLID Principles are five software design principles that help you to write high quality, flexible, maintainable, reusable, testable, and readable software. If you plan to work with object-oriented software, it is crucial to understand these five... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-are-the-solid-principles-in-csharp/</link>
                <guid isPermaLink="false">671a62b68210490d9d68e83f</guid>
                
                    <category>
                        <![CDATA[ Object Oriented Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ C# ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ design patterns ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Engineering ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software architecture ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Danny ]]>
                </dc:creator>
                <pubDate>Thu, 24 Oct 2024 15:07:34 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1729777076695/7d956373-1835-4823-9a6a-d2d232cd64d5.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>The SOLID Principles are five software design principles that help you to write high quality, flexible, maintainable, reusable, testable, and readable software. If you plan to work with object-oriented software, it is crucial to understand these five principles.</p>
<p>The SOLID Principles were introduced by a software engineer named Robert C. Martin (also known as "Uncle Bob") in the early 2000s. Uncle Bob’s goal was to promote good software design practices, particularly in object-oriented programming (OOP), by addressing common problems developers face as software systems grow in size and complexity.</p>
<p>Here are the five SOLID principles:</p>
<ul>
<li><p><strong>S</strong>: <a class="post-section-overview" href="#heading-single-responsibility-principle-srp">Single Responsibility Principle (SRP)</a></p>
</li>
<li><p><strong>O</strong>: <a class="post-section-overview" href="#heading-open-closed-principle-ocp">Open-closed Principle (OCP)</a></p>
</li>
<li><p><strong>L</strong>: <a class="post-section-overview" href="#heading-liskov-substitution-principle-lsp">Liskov Substitution Principle (LSP)</a></p>
</li>
<li><p><strong>I</strong>: <a class="post-section-overview" href="#heading-interface-segregation-principle-isp">Interface Segregation Principle (ISP)</a></p>
</li>
<li><p><strong>D</strong>: <a class="post-section-overview" href="#heading-dependency-inversion-principle-dip">Dependency Inversion Principle (DIP)</a></p>
</li>
</ul>
<p>By following these principles, you can create software designs that are easier to understand, maintain, and extend, leading to higher-quality software that is more robust and adaptable to change.</p>
<p>In this article, to demonstrate each principle, I’ll first show you a bad code example in C# that violates the principle. We will then discuss the issues this bad code causes, and then solve those issues by refactoring the code to satisfy the principle.</p>
<p>First up we have the…</p>
<h2 id="heading-single-responsibility-principle-srp-in-c">Single Responsibility Principle (SRP) in C</h2>
<blockquote>
<p>A class should have only one reason to change, meaning that it should have only one responsibility or purpose.</p>
</blockquote>
<p>This principle encourages you to create classes that are more focussed and perform one single well-defined task, rather than multiple tasks. Breaking up classes into smaller, more focused units makes code easier to understand, maintain, and test.</p>
<p><strong>An example that violates the SRP:</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">User</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Username { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Email { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Register</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-comment">// Register user logic, e.g. save to database...</span>

   <span class="hljs-comment">// Send email notification</span>
   EmailSender emailSender = <span class="hljs-keyword">new</span> EmailSender();
   emailSender.SendEmail(<span class="hljs-string">"Welcome to our platform!"</span>, Email);
 }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">EmailSender</span>
{
 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">SendEmail</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> message, <span class="hljs-keyword">string</span> recipient</span>)</span>
 {
   <span class="hljs-comment">// Email sending logic</span>
   Console.WriteLine(<span class="hljs-string">$"Sending email to <span class="hljs-subst">{recipient}</span>: <span class="hljs-subst">{message}</span>"</span>);
 }
}
</code></pre>
<p>In this example, the <code>User</code> class manages user data (username and email), and contains logic for registering a user. This violates the SRP because the class has more than one reason to change. It could change due to:</p>
<ul>
<li><p>Modifications in user data management – for example adding more fields, such as <code>firstName</code>, <code>gender</code>, <code>hobbies</code>.</p>
</li>
<li><p>Modifications to the logic of registering a user, for example we may choose to fetch a user from the database by their username rather than their email.</p>
</li>
</ul>
<p>To adhere to the Single Responsibility Principle, we should separate these responsibilities into separate classes. </p>
<p><strong>Refactoring the code to satisfy the SRP</strong>:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">User</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Username { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Email { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">EmailSender</span>
{
 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">SendEmail</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> message, <span class="hljs-keyword">string</span> recipient</span>)</span>
 {
   <span class="hljs-comment">// Email sending logic</span>
   Console.WriteLine(<span class="hljs-string">$"Sending email to <span class="hljs-subst">{recipient}</span>: <span class="hljs-subst">{message}</span>"</span>);
 }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">UserService</span>
{
 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">RegisterUser</span>(<span class="hljs-params">User user</span>)</span>
 {
   <span class="hljs-comment">// Register user logic...</span>

   EmailSender emailSender = <span class="hljs-keyword">new</span> EmailSender();
   emailSender.SendEmail(<span class="hljs-string">"Welcome to our platform!"</span>, user.Email);
 }
}
</code></pre>
<p>In the refactored code, the <code>User</code> class is responsible solely for representing user data. The <code>UserService</code> class now handles user registration, separating concerns related to user data management from user registration logic. The <code>UserService</code> class is responsible only for the business logic of registering a user.</p>
<p>This separation of responsibilities adheres to the Single Responsibility Principle, making the code easier to understand, maintain, and extend.</p>
<h2 id="heading-openclosed-principle-ocp-in-c">Open/Closed Principle (OCP) in C</h2>
<blockquote>
<p>Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification.</p>
</blockquote>
<p>This principle promotes the idea that existing code should be able to be extended with new functionality without modifying its source code. It encourages the use of abstraction and polymorphism to achieve this goal, allowing for code to be easily extended through inheritance or composition.</p>
<p>(By the way, if you don’t understand these fundamental OOP concepts, such as abstraction, polymorphism, inheritance and composition — then check out my book, <a target="_blank" href="https://www.amazon.com/Mastering-Design-Patterns-Beginner-Friendly-Principles/dp/B0DB6MLYYZ">Mastering Design Patterns in C#: A Beginner-Friendly Guide, Including OOP and SOLID Principles on Amazon</a> or <a target="_blank" href="https://doabledanny.gumroad.com/l/ennyj?layout=profile">Gumroad</a>.)</p>
<p>Let's consider an example of a <code>Shape</code> class hierarchy that calculates the area of different geometric shapes. Initially, this violates the Open/Closed Principle because adding a new shape requires modifying the existing code:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">enum</span> ShapeType
{
 Circle,
 Rectangle
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">public</span> ShapeType Type { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Radius { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Length { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Width { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">CalculateArea</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">switch</span> (Type)
   {
     <span class="hljs-keyword">case</span> ShapeType.Circle:
       <span class="hljs-keyword">return</span> Math.PI * Math.Pow(Radius, <span class="hljs-number">2</span>);
     <span class="hljs-keyword">case</span> ShapeType.Rectangle:
       <span class="hljs-keyword">return</span> Length * Width;
     <span class="hljs-keyword">default</span>:
       <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> InvalidOperationException(<span class="hljs-string">"Unsupported shape type."</span>);
   }
 }
}
</code></pre>
<p>In this example, the <code>Shape</code> class has a method, <code>CalculateArea()</code>, that calculates the area based on the type of shape. Adding a new shape, such as a triangle, would require modifying the existing <code>Shape</code> class, violating the OCP.</p>
<p>To adhere to the Open/Closed Principle, we should design the system in a way that allows for extension without modification. Let's refactor the code using inheritance and polymorphism:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Shape</span>
{
 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">double</span> <span class="hljs-title">CalculateArea</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Circle</span> : <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Radius { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">double</span> <span class="hljs-title">CalculateArea</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> Math.PI * Math.Pow(Radius, <span class="hljs-number">2</span>);
 }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Rectangle</span> : <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Length { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Width { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">double</span> <span class="hljs-title">CalculateArea</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> Length * Width;
 }
}
</code></pre>
<p>In this refactored code, we define an abstract <code>Shape</code> class with an abstract <code>CalculateArea()</code> method. Concrete shape classes (<code>Circle</code> and <code>Rectangle</code>) inherit from the <code>Shape</code> class and provide their own implementations of <code>CalculateArea()</code>.</p>
<p>Adding a new shape, such as a triangle, would involve creating a new class – <em>extending</em> the codebase – that inherits from <code>Shape</code> and implements <code>CalculateArea()</code>, without <em>modifying</em> existing code. This adheres to the OCP by allowing for extension without modification.</p>
<p>Being able to add functionality without modifying existing code means that we don’t have to worry as much about breaking existing working code and introducing bugs.</p>
<p>Following the OCP encourages us to design our software so that we add new features only by adding new code. This helps us to build loosely-coupled, maintainable software.</p>
<h2 id="heading-liskov-substitution-principle-lsp-in-c">Liskov Substitution Principle (LSP) in C</h2>
<blockquote>
<p>Objects of a superclass should be replaceable with objects of its subclass without affecting the correctness of the program.</p>
</blockquote>
<p>This principle ensures that inheritance hierarchies are well-designed and that subclasses adhere to the contracts defined by their superclasses.</p>
<p>Violations of the LSP can lead to unexpected behavior or errors when substituting objects, making code harder to reason about and maintain.</p>
<p>Let's consider an example involving a <code>Rectangle</code> class and a <code>Square</code> class, which inherit from a common <code>Shape</code> class. Initially, we'll violate the LSP by not adhering to the behavior expected from these classes. Then, we'll fix it to ensure that the principle is respected.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">double</span> Area { <span class="hljs-keyword">get</span>; }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Rectangle</span> : <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">virtual</span> <span class="hljs-keyword">double</span> Width { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-keyword">public</span> <span class="hljs-keyword">virtual</span> <span class="hljs-keyword">double</span> Height { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">double</span> Area =&gt; Width * Height;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Square</span> : <span class="hljs-title">Rectangle</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">double</span> Width
 {
   <span class="hljs-keyword">get</span> =&gt; <span class="hljs-keyword">base</span>.Width;
   <span class="hljs-keyword">set</span> =&gt; <span class="hljs-keyword">base</span>.Width = <span class="hljs-keyword">base</span>.Height = <span class="hljs-keyword">value</span>;
 }

 <span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">double</span> Height
 {
   <span class="hljs-keyword">get</span> =&gt; <span class="hljs-keyword">base</span>.Height;
   <span class="hljs-keyword">set</span> =&gt; <span class="hljs-keyword">base</span>.Height = <span class="hljs-keyword">base</span>.Width = <span class="hljs-keyword">value</span>;
 }
}
</code></pre>
<p>Now, let’s test out if <code>Rectangle</code> calculates its area correctly:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Program.cs</span>

<span class="hljs-keyword">var</span> rect = <span class="hljs-keyword">new</span> Rectangle();
rect.Height = <span class="hljs-number">10</span>;
rect.Width = <span class="hljs-number">5</span>;

System.Console.WriteLine(<span class="hljs-string">"Expected area = 10 * 5 = 50."</span>);

System.Console.WriteLine(<span class="hljs-string">"Calculated area = "</span> + rect.Area);
</code></pre>
<p>Running the program:</p>
<pre><code class="lang-plaintext">Expected area = 10 * 5 = 50.

Calculated area = 50
</code></pre>
<p>Perfect!</p>
<p>Now, in our program, the <code>Square</code> class inherits from, or extends, the <code>Rectangle</code> class, because, mathematically, a square is just a special type of rectangle, where its height equals its width. Because of this, we decided that <code>Square</code> should extend <code>Rectangle</code> – it’s like saying “a square <em>is a</em> (special type of) rectangle”.</p>
<p>But look what happens if we substitute the <code>Rectangle</code> class for the <code>Square</code> class:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> rect = <span class="hljs-keyword">new</span> Square();
rect.Height = <span class="hljs-number">10</span>;
rect.Width = <span class="hljs-number">5</span>;

System.Console.WriteLine(<span class="hljs-string">"Expected area = 10 * 5 = 50."</span>);

System.Console.WriteLine(<span class="hljs-string">"Calculated area = "</span> + rect.Area);
</code></pre>
<pre><code class="lang-plaintext">Expected area = 10 * 5 = 50.

Calculated area = 25
</code></pre>
<p>Oh dear, LSP has been violated: we replaced the object of a superclass (<code>Rectangle</code>) with an object of its subclass (<code>Square</code>), and it affected the correctness of our program. By modeling <code>Square</code> as a subclass of <code>Rectangle</code>, and allowing width and height to be independently set, we violate the LSP. When setting the width and height of a <code>Square</code>, it should retain its squareness, but our implementation allows for inconsistency.</p>
<p>Let’s fix this to satisfy LSP:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">double</span> Area { <span class="hljs-keyword">get</span>; }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Rectangle</span> : <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Width { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Height { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">double</span> Area =&gt; Width * Height;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Square</span> : <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">private</span> <span class="hljs-keyword">double</span> sideLength;

 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> SideLength
 {
   <span class="hljs-keyword">get</span> =&gt; sideLength;
   <span class="hljs-keyword">set</span>
   {
     sideLength = <span class="hljs-keyword">value</span>;
   }
 }

 <span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">double</span> Area =&gt; sideLength * sideLength;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-comment">// Program.cs</span>

Shape rectangle = <span class="hljs-keyword">new</span> Rectangle { Width = <span class="hljs-number">5</span>, Height = <span class="hljs-number">4</span> };

Console.WriteLine(<span class="hljs-string">$"Area of the rectangle: <span class="hljs-subst">{rectangle.Area}</span>"</span>);

Shape square = <span class="hljs-keyword">new</span> Square { SideLength = <span class="hljs-number">5</span> };

Console.WriteLine(<span class="hljs-string">$"Area of the square: <span class="hljs-subst">{square.Area}</span>"</span>);
</code></pre>
<p>In this corrected example, we redesign the <code>Square</code> class to directly set the side length. Now, a <code>Square</code> is correctly modeled as a subclass of <code>Shape</code>, and it adheres to the Liskov Substitution Principle.</p>
<p>How does this satisfy LSP? Well, we have a superclass, <code>Shape</code>, and subclasses <code>Rectangle</code> and <code>Square</code>. Both <code>Rectangle</code> and <code>Square</code> maintain the correct expected behavior of a <code>Shape</code> — we can substitute a square for a rectangle and the area will still be calculated correctly.</p>
<h2 id="heading-interface-segregation-principle-isp-in-c">Interface Segregation Principle (ISP) in C</h2>
<blockquote>
<p>Clients should not be forced to depend on interfaces they do not use.</p>
</blockquote>
<p>This principle encourages the creation of fine-grained interfaces that contain only the methods required by the clients that use them. It helps to prevent the creation of "fat" interfaces that force clients to implement unnecessary methods, leading to cleaner and more maintainable code.</p>
<p>Let's consider an example involving 2D and 3D shapes, initially violating the ISP.</p>
<p><strong>Violating ISP:</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IShape</span>
{
 <span class="hljs-function"><span class="hljs-keyword">double</span> <span class="hljs-title">Area</span>(<span class="hljs-params"></span>)</span>;
 <span class="hljs-function"><span class="hljs-keyword">double</span> <span class="hljs-title">Volume</span>(<span class="hljs-params"></span>)</span>; <span class="hljs-comment">// problem: 2D shapes don't have volume!</span>
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Circle</span> : <span class="hljs-title">IShape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Radius { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">Area</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> Math.PI * Math.Pow(Radius, <span class="hljs-number">2</span>);
 }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">Volume</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> InvalidOperationException(<span class="hljs-string">"Volume not applicable for 2D shapes."</span>);
 }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Sphere</span> : <span class="hljs-title">IShape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Radius { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">Area</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> <span class="hljs-number">4</span> * Math.PI * Math.Pow(Radius, <span class="hljs-number">2</span>);
 }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">Volume</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> (<span class="hljs-number">4.0</span> / <span class="hljs-number">3.0</span>) * Math.PI * Math.Pow(Radius, <span class="hljs-number">3</span>);
 }
}
</code></pre>
<p>In this example, we have an <code>IShape</code> interface representing both 2D and 3D shapes. However, the <code>Volume()</code> method is problematic for 2D shapes, like <code>Circle</code> and <code>Rectangle</code>, because they don't have volume. This violates the ISP because clients (classes using the <code>IShape</code> interface) may be forced to depend on methods they do not need.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> circle = <span class="hljs-keyword">new</span> Circle();
circle.Radius = <span class="hljs-number">10</span>;

System.Console.WriteLine(circle.Area());
System.Console.WriteLine(circle.Volume()); <span class="hljs-comment">// My text editor doesn't flag a problem...</span>

<span class="hljs-keyword">var</span> sphere = <span class="hljs-keyword">new</span> Sphere();
sphere.Radius = <span class="hljs-number">10</span>;

System.Console.WriteLine(sphere.Area());
System.Console.WriteLine(sphere.Volume());
</code></pre>
<p>Usually, if I try to call a method on an object that doesn’t exist, VS Code will tell me that I’m making a mistake. But above, when I call <code>circle.Volume()</code>, VS code is like “no problem”. And VS code is correct, because the <code>IShape</code> interface forces <code>Circle</code> to implement a <code>Volume()</code> method, even though circles don’t have volume.</p>
<p>It’s easy to see how violating ISP can introduce bugs into a program – above, everything looks fine, until we run the program and an exception gets thrown.</p>
<p><strong>Fixing ISP</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IShape2D</span>
{
 <span class="hljs-function"><span class="hljs-keyword">double</span> <span class="hljs-title">Area</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IShape3D</span>
{
 <span class="hljs-function"><span class="hljs-keyword">double</span> <span class="hljs-title">Area</span>(<span class="hljs-params"></span>)</span>;
 <span class="hljs-function"><span class="hljs-keyword">double</span> <span class="hljs-title">Volume</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Circle</span> : <span class="hljs-title">IShape2D</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Radius { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">Area</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> Math.PI * Math.Pow(Radius, <span class="hljs-number">2</span>);
 }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Sphere</span> : <span class="hljs-title">IShape3D</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Radius { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">Area</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> <span class="hljs-number">4</span> * Math.PI * Math.Pow(Radius, <span class="hljs-number">2</span>);
 }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">Volume</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> (<span class="hljs-number">4.0</span> / <span class="hljs-number">3.0</span>) * Math.PI * Math.Pow(Radius, <span class="hljs-number">3</span>);
 }
}
</code></pre>
<p>In the fixed example, we've <em>segregated</em> the <code>IShape</code> interface into two smaller, more focused interfaces: <code>IShape2D</code> and <code>IShape3D</code>. Each shape class now implements only the interface that is relevant to its functionality.</p>
<p>This adheres to the Interface Segregation Principle by ensuring that clients are not forced to depend on methods that they do not use. Clients can now depend only on the interfaces that they need, promoting better code reuse and flexibility.</p>
<p>Next up, the fifth and final SOLID principle…</p>
<h2 id="heading-dependency-inversion-principle-dip-in-c">Dependency Inversion Principle (DIP) in C</h2>
<blockquote>
<p>High-level modules should not depend on low-level modules. Both should depend on abstractions.</p>
</blockquote>
<p>Dependency Inversion is the strategy of depending upon interfaces or abstract classes rather than upon concrete classes. This principle promotes decoupling between modules and promotes the use of interfaces or abstract classes to define dependencies, allowing for more flexible and testable code.</p>
<p>Let's start with an example violating the DIP and then we’ll correct it.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Engine</span> <span class="hljs-comment">// Engine is our "low-level" module</span>
{
 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Start</span>(<span class="hljs-params"></span>)</span>
 {
   System.Console.WriteLine(<span class="hljs-string">"Engine started."</span>);
 }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Car</span> <span class="hljs-comment">// Car is our "high-level" module</span>
{
 <span class="hljs-keyword">private</span> Engine engine;

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Car</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">this</span>.engine = <span class="hljs-keyword">new</span> Engine(); <span class="hljs-comment">// Direct dependency on concrete Engine class</span>
 }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">StartCar</span>(<span class="hljs-params"></span>)</span>
 {
   engine.Start();
   System.Console.WriteLine(<span class="hljs-string">"Car started."</span>);
 }
}
</code></pre>
<p>In this example:</p>
<ul>
<li><p>The <code>Car</code> class directly creates an instance of the <code>Engine</code> class, leading to a tight coupling between Car and Engine.</p>
</li>
<li><p>If the <code>Engine</code> class changes, it may affect the <code>Car</code> class, violating the Dependency Inversion Principle.</p>
</li>
</ul>
<p>The UML diagram below shows that <code>Car</code> depends on <code>Engine</code>:</p>
<p><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdbd6IZ4TfDmGCPIjsJJHTtEw7_WBxCP-H1cSme78Ze7qJq0fG6tQzNo7A-IbgnnruAZwMBhjuJoozA0rzA9RM35Pu9vWpk4I2Hp6Szk7Ns_kTFbu2oIIfHQa9ceBembsjN8EUlZLkQuB863NyzeeSn7qY?key=p75tPpeumlH4kqsSJuxz6w" alt="AD_4nXdbd6IZ4TfDmGCPIjsJJHTtEw7_WBxCP-H1cSme78Ze7qJq0fG6tQzNo7A-IbgnnruAZwMBhjuJoozA0rzA9RM35Pu9vWpk4I2Hp6Szk7Ns_kTFbu2oIIfHQa9ceBembsjN8EUlZLkQuB863NyzeeSn7qY?key=p75tPpeumlH4kqsSJuxz6w" width="600" height="400" loading="lazy"></p>
<p>But what do we mean by “high level” and “low level” classes?</p>
<p><strong>High-Level Class</strong>: The high-level class is typically the one that represents the main functionality or business logic of the application. It orchestrates the interaction between various components and is often more abstract in nature.</p>
<p>In this example, the <code>Car</code> class can be considered the high-level class. It represents the main functionality related to starting the car and driving it. The <code>Car</code> class is concerned with the overall behavior of the car, such as controlling its movement.</p>
<p><strong>Low-Level Class</strong>: The low-level class is usually one that provides specific functionality or services that are used by the high-level class. It typically deals with implementation details and is more concrete in nature.</p>
<p>In this example, the <code>Engine</code> class can be considered the low-level class. It provides the specific functionality related to starting the engine. The <code>Engine</code> class encapsulates the details of how the engine operates, such as ignition and combustion.</p>
<p>So in summary, the <code>Car</code> class is the high-level class, representing the main functionality of the application related to the car's behavior.</p>
<p>The <code>Engine</code> class is the low-level class, providing specific functionality related to the operation of the engine, which is used by the Car class.</p>
<p><strong>Fixing DIP:</strong></p>
<p>To adhere to the Dependency Inversion Principle, we introduce an abstraction (interface) between <code>Car</code> and <code>Engine</code>, allowing <code>Car</code> to depend on an abstraction instead of a concrete implementation.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IEngine</span>
{
 <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">Start</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Engine</span> : <span class="hljs-title">IEngine</span>
{
 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Start</span>(<span class="hljs-params"></span>)</span>
 {
   System.Console.WriteLine(<span class="hljs-string">"Engine started."</span>);
 }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>
{
 <span class="hljs-keyword">private</span> IEngine engine;

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Car</span>(<span class="hljs-params">IEngine engine</span>)</span>
 {
   <span class="hljs-keyword">this</span>.engine = engine;
 }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">StartCar</span>(<span class="hljs-params"></span>)</span>
 {
   engine.Start();
   System.Console.WriteLine(<span class="hljs-string">"Car started."</span>);
 }
}
</code></pre>
<p>We can now <em>inject</em> any type of engine into <code>Car</code> implementations:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> engine = <span class="hljs-keyword">new</span> Engine(); <span class="hljs-comment">// concrete implementation to be "injected" into the car</span>

<span class="hljs-keyword">var</span> car = <span class="hljs-keyword">new</span> Car(engine);

car.StartCar();
</code></pre>
<p>From the UML diagram below, we can see that both objects now depend on the abstraction level of the interface. <code>Engine</code> has inverted its dependency on <code>Car</code>.</p>
<p><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXf2Wes5g5HoeLNGoo4weo-gO6AVdVJ1WbRZxUfTEXIFROup8qCeUiQ8l5CsrwXkC5I1_0i3Q5DyzN5wpXSgjol2_RNFysFKpjMyj4SdEI2lFOplOs-uCUxZGEWE9fI4sFzMKfQOvOx33HKViFcXoqTVmi2s2FcLvCobCCZAvA?key=hfr-bV5v9p97pXexBFuY1A" alt="AD_4nXf2Wes5g5HoeLNGoo4weo-gO6AVdVJ1WbRZxUfTEXIFROup8qCeUiQ8l5CsrwXkC5I1_0i3Q5DyzN5wpXSgjol2_RNFysFKpjMyj4SdEI2lFOplOs-uCUxZGEWE9fI4sFzMKfQOvOx33HKViFcXoqTVmi2s2FcLvCobCCZAvA?key=hfr-bV5v9p97pXexBFuY1A" width="600" height="400" loading="lazy"></p>
<p>In this corrected example:</p>
<ol>
<li><p>We define an interface <code>IEngine</code> representing the behavior of an engine.</p>
</li>
<li><p>The <code>Engine</code> class implements the <code>IEngine</code> interface.</p>
</li>
<li><p>The <code>Car</code> class now depends on the <code>IEngine</code> interface instead of the concrete <code>Engine</code> class.</p>
</li>
<li><p>Dependency injection is used to inject the <code>IEngine</code> implementation into the <code>Car</code> class, promoting loose coupling. Now, if we want to give a car a different type of engine, for example a <code>FastEngine</code>, we can inject that in instead. </p>
</li>
<li><p>Now, if the implementation of the engine changes, it won't affect the <code>Car</code> class as long as it adheres to the <code>IEngine</code> interface.</p>
</li>
</ol>
<p>Dependency Injection (DI) offers several advantages in software development:</p>
<ul>
<li><p><strong>Decoupling</strong>: DI promotes loose coupling between components by removing direct dependencies. Components rely on abstractions rather than concrete implementations, making them more independent and easier to maintain.</p>
</li>
<li><p><strong>Testability</strong>: Dependency injection simplifies unit testing by allowing components to be easily replaced with mock or stub implementations during testing. This enables isolated testing of individual components without relying on their dependencies.</p>
</li>
<li><p><strong>Flexibility</strong>: DI provides flexibility in configuring and swapping dependencies at runtime. It allows different implementations of dependencies to be used interchangeably without modifying the client code, facilitating runtime customization and extensibility.</p>
</li>
<li><p><strong>Readability and Maintainability</strong>: By explicitly specifying dependencies in the constructor or method parameters, DI improves code readability and makes the codebase easier to understand. It also reduces the risk of hidden dependencies, leading to more maintainable and understandable code.</p>
</li>
<li><p><strong>Reusability</strong>: DI promotes component reusability by decoupling them from their specific contexts or environments. Components can be designed to be independent of the application framework or platform, making them more portable and reusable in different projects or scenarios.</p>
</li>
<li><p><strong>Scalability</strong>: DI simplifies the management of dependencies in large-scale applications by providing a standardised approach for dependency resolution. It helps prevent dependency hell and makes it easier to manage and scale complex systems.</p>
</li>
</ul>
<p>Overall, dependency injection enhances modularity, testability, and maintainability of software systems, contributing to improved software quality and developer productivity.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Congratulations – you now understand the extremely important SOLID principles. These principles are going to save you a lot of headaches during your software development career, and guide you towards creating beautiful, maintainable, flexible, testable software.</p>
<p>If you’d like to take your software development skills to the next level and learn:</p>
<ul>
<li><p>OOP principles: encapsulation, abstraction, inheritance, polymorphism, coupling, composition, composition vs inheritance, fragile base class problem.</p>
</li>
<li><p>All 23 design patterns (“The Gang of Four Design Patterns”) with real world examples.</p>
</li>
<li><p>Unified Modeling Language (UML): the standard way to model classes and the relationships between them.</p>
</li>
</ul>
<p>Then check out my book:</p>
<p><a target="_blank" href="https://www.amazon.com/Mastering-Design-Patterns-Beginner-Friendly-Principles/dp/B0DBZGQZMZ">Mastering Design Patterns in C#: A Beginner-Friendly Guide, Including OOP and SOLID Principles on Amazon</a> (also available on <a target="_blank" href="https://doabledanny.gumroad.com/l/ennyj">Gumroad</a>).</p>
<p>Hopefully this article helps you to become a better OOP software developer!</p>
<p>Thanks for reading,</p>
<p><a target="_blank" href="https://www.youtube.com/channel/UC0URylW_U4i26wN231yRqvA">Danny</a> 😎</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Master Object-Oriented Programming and Design Patterns in C# ]]>
                </title>
                <description>
                    <![CDATA[ Understanding design patterns are important for efficient software development. They offer proven solutions to common coding challenges, promote code reusability, and enhance maintainability. By mastering these patterns, developers can create more ro... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/master-object-oriented-programming-and-design-patterns-in-c/</link>
                <guid isPermaLink="false">66ec456516f5ff745e310952</guid>
                
                    <category>
                        <![CDATA[ design patterns ]]>
                    </category>
                
                    <category>
                        <![CDATA[ C# ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Thu, 19 Sep 2024 15:38:13 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1726760279000/2cd9582a-34e1-46dd-8882-d5af45dffe4f.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Understanding design patterns are important for efficient software development. They offer proven solutions to common coding challenges, promote code reusability, and enhance maintainability. By mastering these patterns, developers can create more robust and flexible software, communicate complex ideas effectively, and make better architectural decisions.</p>
<p>We just posted a new course on the freeCodeCamp.org YouTube channel about Object-Oriented Programming (OOP) and Design Patterns. This comprehensive 12-hour course will transform you into an advanced OOP programmer capable of writing clean, maintainable software. This course is created and presented by Dan Adams, an experienced programmer and educator.</p>
<h3 id="heading-course-overview">Course Overview</h3>
<p>This beginner-friendly course covers all the essential tools and concepts you need to excel in object-oriented programming. From fundamental OOP principles to advanced design patterns, you'll gain a thorough understanding of how to create efficient, scalable, and robust software systems.</p>
<p>Here are the key things you will learn about:</p>
<ol>
<li><p><strong>Fundamental OOP Concepts</strong></p>
<ul>
<li><p>Inheritance</p>
</li>
<li><p>Composition</p>
</li>
<li><p>Encapsulation</p>
</li>
<li><p>Abstraction</p>
</li>
<li><p>Composition vs. Inheritance</p>
</li>
<li><p>Fragile Base Class Problem</p>
</li>
</ul>
</li>
<li><p><strong>Unified Modeling Language (UML)</strong></p>
<ul>
<li>Learn to model classes, objects, and their relationships graphically</li>
</ul>
</li>
<li><p><strong>SOLID Principles</strong></p>
<ul>
<li><p>Single Responsibility Principle</p>
</li>
<li><p>Open-Closed Principle</p>
</li>
<li><p>Liskov Substitution Principle</p>
</li>
<li><p>Interface Segregation Principle</p>
</li>
<li><p>Dependency Inversion Principle</p>
</li>
</ul>
</li>
<li><p><strong>23 "Gang of Four" Software Design Patterns</strong></p>
<ul>
<li><p>Behavioral Patterns</p>
</li>
<li><p>Structural Patterns</p>
</li>
<li><p>Creational Patterns</p>
</li>
</ul>
</li>
</ol>
<p>The course is structured to provide a logical progression through the topics:</p>
<ol>
<li><p>Introduction to OOP Concepts</p>
</li>
<li><p>Unified Modeling Language</p>
</li>
<li><p>SOLID Principles</p>
</li>
<li><p>Design Patterns:</p>
<ul>
<li><p>Behavioral Patterns</p>
</li>
<li><p>Structural Patterns</p>
</li>
<li><p>Creational Patterns</p>
</li>
</ul>
</li>
</ol>
<p>Each section is packed with detailed explanations, practical examples, and real-world applications to ensure a comprehensive learning experience.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>This comprehensive course on Object-Oriented Programming and Design Patterns will help you become a more proficient software developer. Watch the full course on <a target="_blank" href="https://youtu.be/rylaiB2uH2A">the freeCodeCamp.org YouTube channel</a> (12-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/rylaiB2uH2A" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create Software Architecture Diagrams Using the C4 Model ]]>
                </title>
                <description>
                    <![CDATA[ As a developer, you'll likely work on a complex project at some point where deciphering the codebase feels like reading a whole novel. Engineers are code wizards, but even the best get lost in sprawling code. The challenge is that architecture diagra... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-software-architecture-diagrams-using-the-c4-model/</link>
                <guid isPermaLink="false">66c636dc83227f02672177db</guid>
                
                    <category>
                        <![CDATA[ Software Engineering ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software architecture ]]>
                    </category>
                
                    <category>
                        <![CDATA[ design patterns ]]>
                    </category>
                
                    <category>
                        <![CDATA[ C4 Model ]]>
                    </category>
                
                    <category>
                        <![CDATA[ diagrams ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Alex Pliutau ]]>
                </dc:creator>
                <pubDate>Wed, 21 Aug 2024 18:50:04 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724187048778/7d2821c6-c0c9-4d03-999f-37022388210c.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>As a developer, you'll likely work on a complex project at some point where deciphering the codebase feels like reading a whole novel. Engineers are code wizards, but even the best get lost in sprawling code.</p>
<p>The challenge is that architecture diagrams – if they even exist – are often outdated relics from a bygone era.</p>
<p>This is why creating and maintaining effective and clear diagrams should be effortless. Up-to-date visuals ensure everyone stays on the same page, eliminating confusion and wasted time.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a target="_blank" href="heading-what-is-the-c4-model">What is the C4 Model?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-level-1-context">Level 1: Context</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-level-2-containers">Level 2: Containers</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-level-3-components">Level 3: Components</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-level-4-code">Level 4: Code</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-supplementary-diagrams">Supplementary Diagrams</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-diagrams-as-code">Diagrams as Code</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-automate-rendering-in-your-ci">Automate Rendering in Your CI</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-resources">Resources</a></p>
</li>
</ul>
<h2 id="heading-what-is-the-c4-model">What is the C4 Model?</h2>
<p>The <a target="_blank" href="https://c4model.com/">C4 model</a> was created as a way to help software development teams describe and communicate software architecture.</p>
<p>C4 stands for “Context, Containers, Components, and Code”. Those are the four levels that should be enough to describe a complex system.</p>
<p>The best way to explain the concept is to think about how we use Google Maps. When we are exploring an area in Google Maps, we will often start zoomed out to help us get context. Once we find the rough area we are interested in we can zoom in to get a little more detail.</p>
<h3 id="heading-level-1-context">Level 1: Context</h3>
<p>This level is the most zoomed out. It's a bird’s eye view of the system in the greater context of the world. The diagram concentrates on actors and systems.</p>
<p>For the examples below, we will use a simple Task Management Software System to demonstrate all these 4 levels.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d096cb9-3058-4bbd-9c69-6a41361e4d3b_1600x2000.png" alt="Diagram showing the context Level" width="1456" height="1820" loading="lazy"></p>
<p>This diagram portrays the Task Management Software System's interactions with external systems and the different user groups that utilize it. We can see that the Task Management software relies on two external systems: Email and Calendar, and two types of actors (users) use it: Customer and Admin User.</p>
<h3 id="heading-level-2-containers">Level 2: Containers</h3>
<p>The containers level is a more detailed view of your system (don’t confuse C4 containers with Docker containers).</p>
<p>It reveals how various functional units like applications and databases work together and distribute responsibilities.</p>
<p>This diagram also highlights the key technologies employed and showcases the communication flow between these containers. It presents a simplified, technology-centric view of the system's core components and their interactions.</p>
<p>If you have Microservice architecture, then each Microservice would be a container.</p>
<p>Examples of containers are:</p>
<ul>
<li><p>Single page application</p>
</li>
<li><p>Web server</p>
</li>
<li><p>Serverless function</p>
</li>
<li><p>Database</p>
</li>
<li><p>API</p>
</li>
<li><p>Message buses</p>
</li>
</ul>
<p>And so on.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb614c4e5-4fbd-4e10-8682-c3e67ec72f2d_3028x2691.png" alt="Diagram showing the Containers Level" width="1456" height="1294" loading="lazy"></p>
<p>This level delves into the internal composition of the Task Management Software System. It showcases that our Task Management software system consists of containers such as User Web UI, Admin Web UI, API and a Database. API is also the container that is connected to external systems, for example to send emails or create events in calendar.</p>
<h3 id="heading-level-3-components">Level 3: Components</h3>
<p>The next level of zoom is components. This shows the major structural building blocks of your application, and is often a conceptual view of the application. The term component is loose here. It could represent a controller or a service containing business logic.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55564aaa-d404-4322-a6f3-9674326410d5_1995x1900.png" alt="Diagram showing the Components Level" width="1456" height="1387" loading="lazy"></p>
<p>This diagram focuses on the internal structure of the API container within the Task Management Software System. It reveals that the API container houses crucial functionalities like CRUD operations (Create, Read, Update, Delete) for data manipulation and user authentication mechanisms. The CRUD components is the one that talks to the database.</p>
<h3 id="heading-level-4-code">Level 4: Code</h3>
<p>The deepest level of zoom is the code diagram. Although this diagram exists, it is often not used as the code paints a very similar picture. However, in highly regulated environments and complex legacy projects this level can help to paint a better picture of inner intricacies of the software.</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde6e40f0-d713-46b9-906e-618fb61eb622_602x339.png" alt="https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde6e40f0-d713-46b9-906e-618fb61eb622_602x339" width="602" height="339" loading="lazy"></p>
<h3 id="heading-supplementary-diagrams">Supplementary Diagrams</h3>
<p>Besides the 4 diagrams above, there are a couple more worth mentioning:</p>
<ul>
<li><p>Deployment diagram</p>
</li>
<li><p>Dynamic diagram: to describe the process or a flow</p>
</li>
</ul>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa13b10a-2093-4ab8-8302-dc75b09be96f_1570x1461.png" alt="Login Flow" width="1456" height="1355" loading="lazy"></p>
<p>On this diagram we show a Login Flow, which is not a container or component, but rather a software process that happens in our software system. It shows that Web/Admin UIs use JWT-based authentication for communication with the API and the JWT token is stored in local storage on a client side.</p>
<h2 id="heading-diagrams-as-code">Diagrams as Code</h2>
<p>The power of C4 comes with a diagram-as-code approach. This means treating your diagrams just like your codebase:</p>
<ul>
<li><p><strong>Version control:</strong> Store them in a source control system (like Git) for easy tracking and collaboration.</p>
</li>
<li><p><strong>Collaboration:</strong> Work together on diagrams using pull requests, similar to code reviews.</p>
</li>
<li><p><strong>Automation:</strong> Integrate them into your build pipelines for automatic rendering with your preferred tools.</p>
</li>
</ul>
<h3 id="heading-helpful-tool-structurizr">Helpful Tool: Structurizr</h3>
<p>There are few tools to help with modeling and diagramming, but the most popular nowadays is <a target="_blank" href="https://www.structurizr.com/">Structurizr</a> with their custom DSL (Domain Specific Language).</p>
<p>All you need is to get familiar with the DSL syntax, which is pretty simple. As long as you get used to it you will be able to create or update diagrams in no time.</p>
<p>Below you can see the DSL for our Task Management Software System.</p>
<pre><code class="lang-bash">workspace {
    model {
        <span class="hljs-comment"># Actors</span>
        customer = person <span class="hljs-string">"Customer"</span> <span class="hljs-string">""</span> <span class="hljs-string">"person"</span>
        admin = person <span class="hljs-string">"Admin User"</span> <span class="hljs-string">""</span> <span class="hljs-string">"person"</span>

        <span class="hljs-comment"># External systems</span>
        emailSystem = softwareSystem <span class="hljs-string">"Email System"</span> <span class="hljs-string">"Mailgun"</span> <span class="hljs-string">"external"</span>
        calendarSystem = softwareSystem <span class="hljs-string">"Calendar System"</span> <span class="hljs-string">"Calendly"</span> <span class="hljs-string">"external"</span>

        <span class="hljs-comment"># Task Management System</span>
        taskManagementSystem  = softwareSystem <span class="hljs-string">"Task Management System"</span>{
            webContainer = container <span class="hljs-string">"User Web UI"</span> <span class="hljs-string">""</span> <span class="hljs-string">""</span> <span class="hljs-string">"frontend"</span>
            adminContainer = container <span class="hljs-string">"Admin Web UI"</span> <span class="hljs-string">""</span> <span class="hljs-string">""</span> <span class="hljs-string">"frontend"</span>
            dbContainer = container <span class="hljs-string">"Database"</span> <span class="hljs-string">"PostgreSQL"</span> <span class="hljs-string">""</span> <span class="hljs-string">"database"</span>
            apiContainer = container <span class="hljs-string">"API"</span> <span class="hljs-string">"Go"</span> {
                authComp = component <span class="hljs-string">"Authentication"</span>
                crudComp = component <span class="hljs-string">"CRUD"</span>
            }
        }

        <span class="hljs-comment"># Relationships (Actors &amp; Systems)</span>
        customer -&gt; webContainer <span class="hljs-string">"Manages tasks"</span>
        admin -&gt; adminContainer <span class="hljs-string">"Manages users"</span>
        apiContainer -&gt; emailSystem <span class="hljs-string">"Sends emails"</span>
        apiContainer -&gt; calendarSystem <span class="hljs-string">"Creates tasks in Calendar"</span>

        <span class="hljs-comment"># Relationships (Containers)</span>
        webContainer -&gt; apiContainer <span class="hljs-string">"Uses"</span>
        adminContainer -&gt; apiContainer <span class="hljs-string">"Uses"</span>
        apiContainer -&gt; dbContainer <span class="hljs-string">"Persists data"</span>

        <span class="hljs-comment"># Relationships (Components &amp; Containers)</span>
        crudComp -&gt; dbContainer <span class="hljs-string">"Reads from and writes to"</span>
        webContainer -&gt; authComp <span class="hljs-string">"Authenticates using"</span>
        adminContainer -&gt; authComp <span class="hljs-string">"Authenticates using"</span>
    }
}
</code></pre>
<p>Let's dive into the most important parts:</p>
<pre><code class="lang-yaml"><span class="hljs-string">workspace</span> [<span class="hljs-string">name</span>] [<span class="hljs-string">description</span>] {
    <span class="hljs-string">model</span> {
    }
}
</code></pre>
<p>Here we define our workspace which should have at least one model. A workspace can optionally be given a name and description.</p>
<pre><code class="lang-yaml"><span class="hljs-string">customer</span> <span class="hljs-string">=</span> <span class="hljs-string">person</span> <span class="hljs-string">"Customer"</span> <span class="hljs-string">""</span> <span class="hljs-string">"person"</span>
<span class="hljs-string">admin</span> <span class="hljs-string">=</span> <span class="hljs-string">person</span> <span class="hljs-string">"Admin User"</span> <span class="hljs-string">""</span> <span class="hljs-string">"person"</span>
</code></pre>
<p>In this section we define our persons (for example, a user, actor, role, or persona) in the following format: <code>person &lt;name&gt; [description] [tags]</code>.</p>
<p>You can use a similar format (name, description, tags) to identify the external systems:</p>
<pre><code class="lang-yaml">        <span class="hljs-string">emailSystem</span> <span class="hljs-string">=</span> <span class="hljs-string">softwareSystem</span> <span class="hljs-string">"Email System"</span> <span class="hljs-string">"Mailgun"</span> <span class="hljs-string">"external"</span>
        <span class="hljs-string">calendarSystem</span> <span class="hljs-string">=</span> <span class="hljs-string">softwareSystem</span> <span class="hljs-string">"Calendar System"</span> <span class="hljs-string">"Calendly"</span> <span class="hljs-string">"external"</span>
</code></pre>
<p>To describe the internal software system we need to write a block that also shows its containers and components:</p>
<pre><code class="lang-yaml"><span class="hljs-string">taskManagementSystem</span>  <span class="hljs-string">=</span> <span class="hljs-string">softwareSystem</span> <span class="hljs-string">"Task Management System"</span>{
    <span class="hljs-string">webContainer</span> <span class="hljs-string">=</span> <span class="hljs-string">container</span> <span class="hljs-string">"User Web UI"</span> <span class="hljs-string">""</span> <span class="hljs-string">""</span> <span class="hljs-string">"frontend"</span>
    <span class="hljs-string">adminContainer</span> <span class="hljs-string">=</span> <span class="hljs-string">container</span> <span class="hljs-string">"Admin Web UI"</span> <span class="hljs-string">""</span> <span class="hljs-string">""</span> <span class="hljs-string">"frontend"</span>
    <span class="hljs-string">dbContainer</span> <span class="hljs-string">=</span> <span class="hljs-string">container</span> <span class="hljs-string">"Database"</span> <span class="hljs-string">"PostgreSQL"</span> <span class="hljs-string">""</span> <span class="hljs-string">"database"</span>
    <span class="hljs-string">apiContainer</span> <span class="hljs-string">=</span> <span class="hljs-string">container</span> <span class="hljs-string">"API"</span> <span class="hljs-string">"Go"</span> {
        <span class="hljs-string">authComp</span> <span class="hljs-string">=</span> <span class="hljs-string">component</span> <span class="hljs-string">"Authentication"</span>
        <span class="hljs-string">crudComp</span> <span class="hljs-string">=</span> <span class="hljs-string">component</span> <span class="hljs-string">"CRUD"</span>
    }
}
</code></pre>
<ul>
<li><p>Container format: <code>container &lt;name&gt; [description] [technology] [tags]</code></p>
</li>
<li><p>Component format: <code>component &lt;name&gt; [description] [technology] [tags]</code></p>
</li>
</ul>
<p>The rest of the model is the most interesting part where we define the relationships between all parts (systems, containers, components):</p>
<pre><code class="lang-yaml"><span class="hljs-string">apiContainer</span> <span class="hljs-string">-&gt;</span> <span class="hljs-string">emailSystem</span> <span class="hljs-string">"Sends emails"</span>
</code></pre>
<p>The following format is used: <code>&lt;identifier&gt; -&gt; &lt;identifier&gt; [description] [technology] [tags]</code>.</p>
<p>There are other features available in Structurizr DSL, such as styling, themes, visibility, etc. You can find find them <a target="_blank" href="https://docs.structurizr.com/dsl/language">here</a>.</p>
<h2 id="heading-automate-rendering-in-your-ci">Automate Rendering in Your CI</h2>
<p>Since you can host your models on GitHub, it is very easy to automate the pipeline for rendering the diagrams in the tools of your choice.</p>
<p>In our case, Structurizr has a GitHub Action that allows you to run <strong>structurizr-cli</strong>, a command line utility for Structurizr that lets you create software architecture models based upon the C4 model using a textual domain specific language (DSL).</p>
<p>This sample repository contains a <a target="_blank" href="https://github.com/plutov/c4-diagram-example/blob/main/.github/workflows/pages.yaml">workflow</a> that simply generates a static page and publishes it to GitHub Pages.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">static</span> <span class="hljs-string">content</span> <span class="hljs-string">to</span> <span class="hljs-string">Github</span> <span class="hljs-string">Pages</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span> [<span class="hljs-string">"main"</span>]

<span class="hljs-attr">permissions:</span>
  <span class="hljs-attr">contents:</span> <span class="hljs-string">read</span>
  <span class="hljs-attr">pages:</span> <span class="hljs-string">write</span>
  <span class="hljs-attr">id-token:</span> <span class="hljs-string">write</span>

<span class="hljs-attr">concurrency:</span>
  <span class="hljs-attr">group:</span> <span class="hljs-string">"pages"</span>
  <span class="hljs-attr">cancel-in-progress:</span> <span class="hljs-literal">false</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">container:</span>
      <span class="hljs-attr">image:</span> <span class="hljs-string">ghcr.io/avisi-cloud/structurizr-site-generatr</span>
      <span class="hljs-attr">options:</span> <span class="hljs-string">--user</span> <span class="hljs-string">root</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Create</span> <span class="hljs-string">site</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">|
          /opt/structurizr-site-generatr/bin/structurizr-site-generatr generate-site -w diagram.dsl
</span>      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/upload-artifact@v3</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">name:</span> <span class="hljs-string">website</span>
          <span class="hljs-attr">path:</span> <span class="hljs-string">build/site</span>
  <span class="hljs-attr">deploy:</span>
    <span class="hljs-attr">needs:</span> <span class="hljs-string">build</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-attr">name:</span> <span class="hljs-string">github-pages</span>
      <span class="hljs-attr">url:</span> <span class="hljs-string">${{</span> <span class="hljs-string">steps.deployment.outputs.page_url</span> <span class="hljs-string">}}</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/download-artifact@v3</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">name:</span> <span class="hljs-string">website</span>
          <span class="hljs-attr">path:</span> <span class="hljs-string">build/site</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Setup</span> <span class="hljs-string">Pages</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/configure-pages@v3</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Upload</span> <span class="hljs-string">artifact</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/upload-pages-artifact@v1</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">path:</span> <span class="hljs-string">"build/site"</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">GitHub</span> <span class="hljs-string">Pages</span>
        <span class="hljs-attr">id:</span> <span class="hljs-string">deployment</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/deploy-pages@v2</span>
</code></pre>
<p>This Github Action uses Structurizr CLI action to compile our DSL file as HTML and publish it to Github Pages.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>I believe that creating and maintaining effective and clear diagrams should be effortless. Up-to-date visuals ensure everyone stays on the same page, eliminating confusion and wasted time.</p>
<p>The C4 model and a bit of automation with Structurizr DSL can help make this process faster and keep diagrams close to the codebase. The whole process can now be automated as well into your SDLC.</p>
<h3 id="heading-resources">Resources</h3>
<ul>
<li><p><a target="_blank" href="https://github.com/plutov/c4-diagram-example">Github Repository</a></p>
</li>
<li><p><a target="_blank" href="https://c4model.com/">C4 Model</a></p>
</li>
<li><p><a target="_blank" href="https://docs.structurizr.com/dsl/language">DSL Language Reference</a></p>
</li>
<li><p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=systemticks.c4-dsl-extension">C4 DSL Visual Studio Code Extension</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/marketplace/actions/structurizr-cli-action">structurizr-cli-action</a></p>
</li>
<li><p><a target="_blank" href="https://packagemain.tech">Discover more articles from packagemain.tech</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
