Showing posts with label Best Practices. Show all posts
Showing posts with label Best Practices. Show all posts

Thursday, 7 November 2013

Memento Design pattern - KeyPoints

🚀 Master Java Design Patterns & Software Architecture!

Subscribe to Ram N Java for clean software architecture patterns, design pattern deep dives, and production-ready implementation guides!

🔔 Subscribe to Ram N Java

Key Takeaways: Memento Design Pattern

The Memento Design Pattern is a foundational Gang of Four (GoF) behavioral pattern engineered to capture and externalize an object’s internal state so that it can be restored later without violating encapsulation. Understanding the core takeaways, essential rules, and trade-offs of this pattern enables software engineers to implement clean undo/redo mechanisms, transaction rollbacks, and recovery checkpoints in enterprise systems.

Core Concepts & Architecture

  • Encapsulation Integrity: The primary objective of the Memento pattern is safeguarding encapsulation boundaries. State details remain private to the Originator and completely opaque to the Caretaker.
  • Distinct Separation of Roles: The pattern relies on three distinct collaborators: the Originator (state owner), the Memento (state snapshot), and the Caretaker (state manager).
  • Wide vs. Narrow Interface: A standard memento architecture presents two interfaces: a wide interface accessible only to the Originator (allowing full state extraction/restoration) and a narrow interface to the Caretaker (preventing inspection or mutation of state fields).
  • Immutability of Snapshots: Once a Memento is created, its captured state should never be modified.

When Should You Apply the Memento Pattern?

  1. Undo and Redo Functionality: When building interactive user interfaces, text editors, canvas applications, or graphic editors that require multi-level rollbacks.
  2. Transactional Integrity & Rollback: When an operation may fail midway and requires rolling back to a known stable snapshot without re-instantiating the entire object.
  3. Checkpoint and State Persistence: When saving game progress, multi-step wizard form sessions, or system configuration recovery points.

Advantages & Trade-Offs

  • Zero Exposure of Private Data: Eliminates antipatterns like exposing internal fields via public getters and setters solely for snapshotting.
  • Simplified Originator Code: Offloads checkpoint storage, history management, and stack tracking entirely to the Caretaker.
  • Memory Footprint Consideration: Storing numerous full-state snapshots can consume substantial memory. For high-volume states, consider delta-based storage or limiting history capacity.

Recommended Next Videos

Continue your deep dive into the Memento pattern and behavioral design patterns with these related tutorials from our channel:


Click here to watch in Youtube : https://www.youtube.com/watch?v=72U7hbxHCUw

Click the below Image to Enlarge


















See also:

  • Momento Design pattern - Introduction
  • Momento Design pattern - Real time Example
  • Memento Design pattern - Class Diagram
  • Memento Design pattern - Sequence Diagram
  • Memento Design pattern - Implementation
  • All Design Patterns Links
  • Friday, 30 August 2013

    Iterator Design Pattern - Implementation

    🚀 Master Java Design Patterns & Software Architecture!

    Subscribe to Ram N Java for clean software architecture patterns, design pattern deep dives, and production-ready implementation guides!

    🔔 Subscribe to Ram N Java

    Implementing the Iterator Design Pattern in Java

    The Iterator Design Pattern is one of the most widely used behavioral patterns in software engineering. While the concept of stepping through elements sequentially is straightforward, creating a robust, reusable implementation requires adhering to sound design principles. Implementing the pattern correctly ensures that custom aggregate structures—such as trees, custom lists, or graph nodes—can be traversed predictably without exposing internal data structures or creating concurrent modification bugs.

    Key Components & Architecture

    • The Iterator Interface: Declares core traversal operations such as hasNext(), next(), and optionally remove().
    • The Concrete Iterator: Implements the interface, maintains the internal cursor position, and directly queries the collection to retrieve items in sequential order.
    • The Aggregate / Container Interface: Defines factory methods (e.g., createIterator() or Java's iterator() via Iterable<T>) to decouple the creation of iterators from client code.
    • The Concrete Aggregate: Manages internal data storage and instantiates the concrete iterator with a reference to itself.

    Implementation Best Practices

    1. Implement Standard Interfaces: Leverage Java's built-in Iterable<T> and Iterator<T> interfaces so your custom collections seamlessly integrate with enhanced for-each loops and Stream APIs.
    2. Guard Against Fail-Fast Scenarios: Track structural modifications (like a modCount variable) to detect concurrent modifications and immediately throw ConcurrentModificationException if the collection is altered outside the iterator.
    3. Encapsulate Concrete Iterators: Declare concrete iterators as private inner or package-private classes within the aggregate to protect internal structural references from external tampering.
    4. Handle Boundaries Gracefully: Ensure next() throws NoSuchElementException when called without checking hasNext(), avoiding silent failures or null pointer exceptions.

    Why Proper Implementation Matters

    • Polymorphic Iteration: Clients can write uniform traversal algorithms that work identically across arrays, trees, linked nodes, or custom data structures.
    • Concurrent Traversals: Multiple clients can simultaneously iterate over the same aggregate without race conditions, since each iterator holds its own independent cursor.
    • Clean Separation of Concerns: The aggregate class stays focused strictly on data storage, while traversal mechanics remain isolated in dedicated iterator objects.

    Recommended Next Videos

    Continue your deep dive into behavioral patterns and collection traversal with these related guides from our channel:


    Click here to watch in Youtube : https://www.youtube.com/watch?v=uRiKSJAnmeA

    Click the below Image to Enlarge
    Iterator Design Pattern - Implementation

















    IteratorPatternDemo.Java

    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Set;

    public class IteratorPatternDemo
    {

    public static void main( String[] args )
    {
    ArrayList<String> listOfCountries = new ArrayList<String>();
    listOfCountries.add("India");
    listOfCountries.add("US");
    listOfCountries.add("Japan");
    listOfCountries.add("France");

    Iterator<String> iterator = listOfCountries.iterator();
    System.out.println("Iterator type for the Datastructure ArrayList : "+iterator.toString());
    System.out.println();
    while( iterator.hasNext() )
    {
    String countryName = iterator.next();
    System.out.println("Country Name : " + countryName);
    }
    System.out.println();
    Set<String> setOfCountries = new HashSet<String>();
    setOfCountries.add("India");
    setOfCountries.add("US");
    setOfCountries.add("Japan");
    setOfCountries.add("France");
    Iterator<String> iterator1 = setOfCountries.iterator();
    System.out.println("Iterator type for the Datastructure HashSet : "+iterator1.toString());
    System.out.println();
    while( iterator1.hasNext() )
    {
    String countryName = iterator1.next();
    System.out.println("Country Name : " + countryName);
    }

    }

    }

    Output

    Iterator type for the Datastructure ArrayList : java.util.AbstractList$Itr@12dacd1

    Country Name : India
    Country Name : US
    Country Name : Japan
    Country Name : France

    Iterator type for the Datastructure HashSet : java.util.HashMap$KeyIterator@30c221

    Country Name : France
    Country Name : US
    Country Name : Japan
    Country Name : India

    Saturday, 24 August 2013

    Object Pool Design Pattern - Implementation

    🚀 Master Java Design Patterns & Software Architecture!

    Subscribe to Ram N Java for clean software architecture patterns, design pattern deep dives, and production-ready implementation guides!

    🔔 Subscribe to Ram N Java

    Implementing the Object Pool Pattern in Java

    While the concept behind the Object Pool Design Pattern is straightforward—reusing expensive objects rather than constantly allocating and garbage collecting them—implementing a robust, production-grade object pool requires careful design. From managing thread safety in concurrent environments to handling object state resets and timeout strategies, adhering to sound engineering practices ensures your pool performs reliably under high load.

    Key Components of a Robust Pool

    • Internal Collections: The pool typically manages two synchronized collections: an available/idle pool ready for checkout and an in-use/locked tracking structure to monitor borrowed instances.
    • Acquisition Logic (checkOut): When a client requests an instance, the pool validates and returns an idle object. If none are available and capacity limits allow, a new instance is created; otherwise, the request waits or throws an exhaustion exception.
    • Release & Reset Logic (checkIn): When a client returns an object, the pool must scrub or reset its internal state so the next borrower receives a clean, uncompromised instance.
    • Validation & Expiration: Periodic health checks or pre-checkout validations ensure that stale, broken, or expired resources (like dropped network sockets) are purged and replaced.

    Implementation Best Practices

    1. Ensure Thread Safety: Protect internal pool state using concurrent data structures (e.g., BlockingQueue, ConcurrentLinkedQueue) or synchronized methods to prevent race conditions during checkout and checkin.
    2. Always Reset Object State: Never return a dirty object to the idle pool. Implement a dedicated reset() or clean() lifecycle method to clear sensitive client data or lingering configuration.
    3. Configure Explicit Boundaries: Define appropriate minIdle, maxIdle, and maxTotal limits to prevent runaway memory consumption while maintaining sufficient headroom for traffic spikes.
    4. Handle Leaks with AutoCloseable: Wrap borrowed objects in try-with-resources blocks implementing AutoCloseable so resources automatically return to the pool even if exceptions occur.

    Why Proper Implementation Matters

    • Deterministic Resource Usage: Hard boundaries prevent memory bloat and external system overload (such as exhausting database server threads).
    • Predictable Low Latency: Zero-allocation checkout eliminates pauses caused by object instantiation and heavy garbage collector runs.
    • Fault Resilience: Active health-checking guarantees that calling code only receives valid, operational resources.

    Recommended Next Videos

    Continue your deep dive into resource pooling and creational patterns with these related tutorials from our channel:


    Click here to watch in Youtube : https://www.youtube.com/watch?v=GE6-cy77Cec

    Click the below Image to Enlarge
    Object Pool Design Pattern - Implementation

    Tuesday, 13 August 2013

    Singleton Design Pattern - Implementation

    🚀 Master Java Design Patterns & Software Architecture!

    Subscribe to Ram N Java for clean software architecture patterns, design pattern deep dives, and production-ready implementation guides!

    🔔 Subscribe to Ram N Java

    Implementing the Singleton Pattern in Production Java

    While the conceptual foundation of the Singleton pattern is simple—restricting instance creation to a single object—building a bulletproof singleton in production Java requires dealing with concurrency, reflection attacks, serialization integrity, and classloader isolation. A naive singleton implementation that works in single-threaded tests can break under concurrent multi-threaded execution or bypass restrictions via Java reflection.

    Common Singleton Implementation Strategies

    • Eager Initialization: The singleton instance is initialized statically during class loading. It is thread-safe and simple, but allocates resources upfront regardless of whether the instance is ever consumed.
    • Synchronized Method (Lazy): Synchronizing the entire getInstance() method ensures thread safety during lazy instantiation, but incurs unnecessary lock contention and performance overhead on subsequent reads.
    • Double-Checked Locking (DCL): Checks the instance twice with synchronized locking around the creation block, utilizing a volatile field to prevent instruction reordering issues.
    • Bill Pugh Singleton (Static Holder): Utilizes an inner static helper class to achieve lazy loading and full thread safety without explicit synchronization locks.
    • Enum Singleton: Recommended by Joshua Bloch, an enum with a single value provides natural protection against reflection attacks and handles serialization automatically out of the box.

    Key Best Practices & Pitfalls to Avoid

    1. Always Guard Against Reflection: Malicious code or frameworks can use setAccessible(true) on private constructors. Throw an exception from within the constructor if an instance already exists.
    2. Implement readResolve() for Serializable Singletons: De-serialization creates a fresh object by default, breaking the pattern. Providing the readResolve() method guarantees the existing instance is returned.
    3. Use Volatile with Double-Checked Locking: Declaring the instance variable as volatile ensures cross-thread memory visibility and prevents out-of-order execution hazards during initialization.
    4. Clone Protection: Override clone() and throw a CloneNotSupportedException to prevent duplicating instances via object cloning.

    Why Proper Implementation Matters

    • Thread Safety Guarantee: Prevents subtle race conditions and duplicate instance allocations under heavy multithreaded loads.
    • Resilience to Advanced Java APIs: Protects application state from being bypassed by reflection, serialization, or cloning mechanisms.
    • Optimal Resource Utilization: Delivers clean lazy loading without continuous runtime locking overhead.

    Recommended Next Videos

    Deepen your mastery of singleton design and concurrency patterns with these related tutorials from our channel:


    Click here to watch in Youtube : https://www.youtube.com/watch?v=zFo0tj84Abc

    Click the below Image to Enlarge

    Singleton Design Pattern - Implementation

























    See also:

  • Singleton Design Pattern - Introduction
  • Singleton Design Pattern - Java Code
  • Singleton Design Pattern - key Points
  • All Design Patterns Links
  • Tutorials