Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Design Patterns For Developers

Design Patterns For Developers

Conducted at the Faculty of Information Technology of University of Moratuwa, Sri Lanka on 11/10/2023. This lecture focuses on basic introduction to design patterns.

Related quiz is available at: https://forms.gle/26wb53KLZsg1Dx1s7
Source code: https://github.com/nishanc/AngularDotnetAuthDemo

Nishan Chathuranga

October 01, 2023
Tweet

More Decks by Nishan Chathuranga

Other Decks in Education

Transcript

  1. Design Patterns
    For Developers
    NISHAN
    WICKRAMARATHNA
    Associate Technical Lead
    Xeynergy LLC
    By
    Singleton Factory
    Decorator Adaptor
    Observer
    MVC Proxy
    Abstract Factory
    Builder Abstract Builder Dependency Injection

    View full-size slide

  2. Design Patterns
    Singleton
    Factory Decorator
    Adaptor Observer
    MVC
    Proxy
    Abstract Factory
    Builder
    Abstract Builder
    Dependency Injection
    Behavioral
    Design Patterns
    Creational
    Design Patterns
    Structural Design
    Patterns

    View full-size slide

  3. Design Patterns
    Singleton
    Factory Decorator
    Adaptor Observer
    MVC
    Proxy
    Abstract Factory
    Builder
    Abstract Builder
    Dependency Injection
    Behavioral
    Design Patterns
    Creational
    Design Patterns
    Structural Design
    Patterns

    View full-size slide

  4. Creational Design Patterns
    • Purpose: Creational patterns deal with object
    creation mechanisms, trying to create objects in a
    manner suitable for the situation.
    • Usage: They are used when a system should be
    independent of how its objects are created,
    composed, and represented, and when the system
    is configured with multiple families of objects.
    • Common Scenario: Creating and managing
    instances of classes while encapsulating their
    creation logic, such as ensuring a class has only
    one instance (Singleton), or creating objects
    based on certain conditions (Factory, Abstract
    Factory).

    View full-size slide

  5. Structural Design Patterns Purpose: Structural patterns are concerned with
    object composition, allowing objects to form larger
    structures or adapt to new functionalities by
    composing objects.
    Usage: They are used when you want to ensure that a
    system's structure is flexible and efficient and when
    you need to manage relationships between objects to
    form larger, more complex structures.
    Common Scenario: Adapting an interface to make it
    compatible with another (Adapter), adding
    responsibilities to objects dynamically (Decorator), or
    controlling access to an object (Proxy).

    View full-size slide

  6. Behavioral Design Patterns
    Purpose: Behavioral patterns focus on the
    interactions and communication between objects,
    defining how they collaborate and operate together.
    Usage: They are used when you need to manage the
    responsibilities of objects and the protocols for
    communication between them in a flexible and
    decoupled manner.
    Common Scenario: Implementing a publish-subscribe
    mechanism for notifying multiple objects of state
    changes (Observer), separating the concerns of an
    application into Model, View, and Controller (MVC), or
    achieving loose coupling between classes by injecting
    dependencies from external sources (DI).

    View full-size slide

  7. Our Focus Today
    Problem Solution Consequences
    When to apply the
    pattern, explains the
    problem and its
    context
    Elements that make
    up the design, their
    relationships,
    responsibilities, and
    collaborations
    Results and trade-offs
    of applying the
    pattern

    View full-size slide

  8. Before We Start
    Basic Understanding of
    OOP Concepts
    Design Patterns
    Hands On Exeperience
    About a Object
    Oriented Programming
    language like Java / C#
    Source Code

    View full-size slide

  9. Singleton
    • When you need to ensure that a class has only one instance and provide a global point of
    access to that instance.
    • When you want to control access to shared resources, such as a database connection or a
    configuration manager.
    • Create a private, static instance of the class within itself.
    • Define a private constructor to prevent external instantiation.
    • Provide a public static method that returns the single instance.
    Problem
    Solution
    Think of it as a president's office. There is only
    one president, and everyone accesses that
    office through a single entrance.
    The Singleton pattern ensures that a class has
    only one instance and provides a global point
    of access to that instance.
    Click to see the example

    View full-size slide

  10. Singleton
    • Provides a single point of control for the instance.
    • Lazily initializes the instance when first requested.
    • Can lead to issues with multi-threaded access (may require synchronization).
    • May make unit testing difficult due to tight coupling.
    Consequence
    There is only one Instance of the object, so if it becomes
    corrupted, the entire system is compromised

    View full-size slide

  11. Factory
    • When you want to create objects without specifying the exact class of object that will be
    created.
    • When you need to centralize object creation to simplify object management and decouple
    client code from concrete classes.
    • Define an interface or base class for the product.
    • Create concrete classes that implement the product interface.
    • Create a factory class responsible for creating instances of the concrete products based on
    input parameters.
    Problem
    Solution
    It's like a car factory where you provide
    specifications, and the factory builds a car
    based on those specs.
    The Factory pattern is used to create objects
    without specifying the exact class of object
    that will be created.

    View full-size slide

  12. Factory
    • Encapsulates object creation logic.
    • Provides flexibility to change the product creation without modifying client code.
    • Can make the code more complex with the introduction of multiple factory classes.
    • May require modification to the factory when new products are added.
    Consequence
    It can increase the complexity and size of the code, as you
    need to create a separate factory class or method for
    each type of object.

    View full-size slide

  13. Abstract Factory
    • When you need to create families of related or dependent objects without specifying their
    concrete classes.
    • When you want to ensure that the created objects are compatible and work together.
    • Define abstract factory interfaces for creating product families.
    • Create concrete factory classes for each product family.
    • Define abstract product interfaces for each product type within a family.
    • Create concrete product classes that implement the product interfaces.
    Problem
    Solution
    Think of it as a furniture factory that
    produces chairs, tables, and sofas. You can
    choose a modern or Victorian factory, and it
    will create a whole set of matching furniture.
    Provides an interface for creating families of
    related or dependent objects without
    specifying their concrete classes.

    View full-size slide

  14. Abstract Factory
    • Ensures that products created by a factory are compatible.
    • Provides an easy way to switch between different families of objects.
    • Can be complex when there are many product families and their variations.
    • Requires adding new factory and product classes when introducing new families.
    Consequence
    Difficult to support new kinds of products: Extending
    abstract factories to produce new kinds of Products isn’t
    easy. That’s because the AbstractFactory interface fixes
    the set of products that can be created. Supporting new
    kinds of products requires extending the factory interface,
    which involves changing the AbstractFactory class and all
    its subclasses.

    View full-size slide

  15. Builder
    • When you need to construct a complex object with many optional components and
    configurations.
    • When you want to separate the construction process from the representation of the object.
    • Define a Director class that orchestrates the construction process.
    • Create a Builder interface with methods for building various parts of the object.
    • Implement concrete Builder classes that build different variations of the object.
    • Provide a method for retrieving the constructed object.
    Problem
    Solution
    Imagine ordering a custom burger. You
    specify the type of bun, patty, toppings, and
    condiments to build your unique burger.
    Separates the construction of a complex
    object from its representation, allowing the
    same construction process to create
    different representations.

    View full-size slide

  16. Builder
    • Allows for the construction of complex objects step by step.
    • Isolates the client code from the details of object construction.
    • Can lead to the creation of many builder classes for different object types.
    • May require clients to interact with the Director, which might not be needed in simple
    cases.
    Consequence
    The main hazard of this design pattern is that needs to
    create a separate Builder for each type of the desired
    product.

    View full-size slide

  17. Abstract Builder
    • When you need to extend the Builder pattern to support the construction of complex objects with
    multiple variations and configurations.
    • When you want to ensure that a family of related builders adheres to a common construction
    process.
    • Define an abstract builder interface with methods for building various parts of the complex object.
    • Create concrete builder classes for each variation of the complex object, implementing the abstract
    builder interface.
    • Define a director class that works with abstract builders and orchestrates the construction process.
    • Provide a way for clients to use the director to construct the desired complex object.
    Problem
    Solution
    Think of building a computer where you
    have different manufacturers for
    components like CPU, RAM, and storage, but
    they all follow a common assembly process.
    The Abstract Builder pattern extends the
    Builder pattern by defining an abstract
    interface for creating complex objects.

    View full-size slide

  18. Abstract Builder
    • Supports the construction of complex objects with multiple variations and configurations.
    • Ensures a common construction process for related complex objects.
    • May lead to the creation of multiple builder classes, which can be complex to manage.
    • Provides flexibility but may require more code and classes compared to the basic Builder
    pattern.
    Consequence
    The use of the builder pattern can make the code more
    verbose and harder to read, because it involves creating
    separate classes for the builder and the object being
    built.

    View full-size slide

  19. Decorator
    • When you need to add responsibilities to objects dynamically without altering their structure.
    • When you want to create a flexible way to extend the behavior of objects.
    • Define a component interface that represents the objects to which responsibilities can be added.
    • Create concrete component classes that implement the component interface.
    • Define a decorator interface that also implements the component interface.
    • Create concrete decorator classes that wrap concrete components and add or override their
    behavior.
    • Clients interact with decorated objects, which can have multiple decorators.
    Problem
    Solution
    Think of ordering a coffee with options for
    extra toppings like whipped cream, caramel,
    or chocolate. You can keep adding toppings
    without changing the base coffee.
    The Decorator pattern allows you to attach
    additional behaviors or responsibilities to an
    object dynamically, without altering its
    structure.

    View full-size slide

  20. Decorator
    • Allows for adding responsibilities to objects dynamically.
    • Provides a flexible alternative to subclassing for extending object behavior.
    • Can lead to many small classes when there are many combinations of decorators.
    • May require careful ordering of decorators to achieve the desired behavior.
    Consequence
    It can introduce a lot of small objects in your system,
    which can increase the memory usage and the complexity
    of debugging.

    View full-size slide

  21. Adapter
    • When you have an existing class with an interface that does not match the interface expected by the
    client code.
    • When you want to make existing classes work with other classes without modifying their source
    code.
    • Create an adapter class that implements the expected interface.
    • Inside the adapter, delegate calls to the methods of the existing class.
    • The client code interacts with the adapter, which translates calls to the appropriate methods of the
    existing class.
    Problem
    Solution
    Think of a travel adapter that lets you use
    your devices with different types of power
    outlets when traveling abroad.
    The Adapter pattern allows the interface of
    an existing class to be used as another
    interface, making it compatible with
    different client code.

    View full-size slide

  22. Adapter
    • Allows existing classes to work with new client code without modification.
    • Enables interoperability between different classes and systems.
    • Can introduce an additional layer of complexity in the code.
    • May require creating multiple adapters for different classes or interfaces.
    Consequence
    It introduces additional overhead and complexity to your
    code. The adapter class acts as an intermediary between
    the two interfaces, which means that it must perform
    extra operations to convert the data, handle exceptions,
    and delegate calls.

    View full-size slide

  23. Observer
    • When you want to establish a one-to-many relationship between objects, so that when one object
    changes state, all its dependents are notified and updated automatically.
    • When you need to maintain consistency between related objects without tight coupling.
    • Define a subject (observable) interface with methods to attach, detach, and notify observers.
    • Create concrete subject classes that implement the subject interface and maintain a list of
    registered observers.
    • Define an observer interface with an update method.
    • Create concrete observer classes that implement the observer interface and specify how they
    respond to updates.
    • Subjects notify all registered observers when their state changes.
    Problem
    Solution
    Think of subscribing to a newsletter. When
    there's a new issue, all subscribers receive a
    copy without the sender needing to notify
    each one individually.
    The Observer pattern defines a one-to-many
    dependency between objects, so that when
    one object changes state, all its dependents
    are notified and updated automatically.

    View full-size slide

  24. Observer
    • Supports loose coupling between subjects and observers.
    • Allows multiple objects to be notified of changes in a subject's state.
    • Can lead to potential performance issues if there are many observers.
    • Observers may become tightly coupled to the subject if they rely heavily on its internal
    state.
    Consequence
    If it is not implemented carefully, it will be the cause of
    large complexity code and subscribers are notified in
    random order.
    There is also a memory leakage problem in the observer
    design pattern because of the observer's explicit register
    and unregistering.

    View full-size slide

  25. MVC (Model-View-Controller)
    • When you need to separate the concerns of an application into three interconnected components:
    Model (data and logic), View (presentation), and Controller (user input handling).
    • When you want to improve maintainability and modularity by decoupling the user interface from
    the application logic.
    • Model represents the application's data and business logic.
    • View displays the data to the user and handles user interface elements.
    • Controller handles user input, updates the model, and communicates with the view.
    • The model notifies the view of changes, and the view updates itself accordingly.
    • The controller acts as an intermediary between the model and view, facilitating user interactions.
    Problem
    Solution
    Think of a restaurant. The kitchen (Model)
    prepares the food, the waitstaff (Controller)
    takes orders and serves food, and diners
    (View) see and interact with the food.
    The MVC pattern separates an application
    into three interconnected components:
    Model (data and logic), View (presentation),
    and Controller (user input handling).

    View full-size slide

  26. MVC (Model-View-Controller)
    • Separates concerns and promotes a modular architecture.
    • Enhances code maintainability and testability.
    • Can introduce complexity due to the need for coordination between the components.
    • Requires careful design to ensure that each component's responsibilities are well-defined.
    Consequence
    It can increase the complexity and overhead of your code.
    Because you must create and manage three components,
    you may end up with more files, classes, and functions
    than necessary.

    View full-size slide

  27. Proxy
    • When you want to control access to an object by introducing an intermediary (proxy) that acts as a
    surrogate.
    • When you need to add extra functionality like lazy loading, access control, or logging to an object
    without changing its code.
    • Create a proxy class that implements the same interface as the real object.
    • Forward calls from the proxy to the real object, performing additional tasks if needed.
    • Clients interact with the proxy, which delegates the requests to the real object when necessary.
    Problem
    Solution
    Imagine a security guard who controls
    access to a building. People can't enter the
    building directly; they go through the
    security guard, who checks their credentials
    and grants access accordingly.
    The Proxy pattern provides a surrogate or
    placeholder for another object to control
    access to it, adding extra functionality or
    controlling access in various ways.

    View full-size slide

  28. Proxy
    • Allows for controlling access to an object and adding behavior transparently.
    • Can improve performance by deferring object creation or initialization until it's needed.
    • May introduce an additional layer between the client and the real object, potentially
    impacting performance.
    • Requires careful design to ensure that the proxy and real object maintain the same
    interface.
    Consequence
    This pattern adds another layer of abstraction, which can
    occasionally cause problems if some clients access the
    Real subject code directly while others might access the
    Proxy classes. This could cause inconsistent behavior.

    View full-size slide

  29. Dependency Injection (DI)
    • When you want to promote loose coupling between classes and allow dependencies to be injected
    from external sources.
    • When you need to make your code more testable by easily substituting dependencies with mock
    objects.
    • Define classes that have dependencies on other classes or services as constructor parameters or
    properties.
    • Inject the required dependencies from external sources, typically using a dependency injection
    container or manually through code.
    • Allow the client code or a container to provide the necessary dependencies when creating instances
    of the class.
    Problem
    Solution
    Consider a chef who needs specific
    ingredients to cook a dish. Instead of
    growing those ingredients themselves, they
    are delivered to the chef.
    The Dependency Injection pattern allows you
    to inject dependencies (e.g., services,
    objects) into a class rather than creating
    them within the class, promoting decoupling
    and testability.

    View full-size slide

  30. Dependency Injection (DI)
    • Promotes loose coupling and decouples classes from their dependencies.
    • Enhances testability by allowing the injection of mock objects for testing.
    • Can introduce complexity, especially when managing the configuration of dependencies.
    • Requires a proper understanding of dependency injection patterns and practices to be
    effectively implemented.
    Consequence
    Increased boilerplate due to injecting dependencies, a
    higher learning curve, and potential performance issues.
    You need to write more code to create and pass them
    around, either manually or using a framework or a
    container.

    View full-size slide

  31. In Real Applications…
    Singleton Pattern:
    Database Connection Pool: Ensures that only one connection to the database is maintained throughout the
    application.
    Factory Pattern:
    GUI Library: Different GUI elements like buttons, text fields, and checkboxes are created using a factory
    pattern to ensure consistent UI creation.
    Abstract Factory Pattern:
    Cross-Platform UI: Abstract factory can be used to create UI components (buttons, windows, etc.) that work
    on different operating systems.
    Builder Pattern:
    StringBuilder in Java: It allows you to build a complex string step by step efficiently.
    Abstract Builder Pattern:
    Document Builders: For creating documents in various formats (e.g., PDF, HTML), an abstract builder can
    define the steps to build a document, while concrete builders implement the format-specific details.
    Decorator Pattern:
    Java I/O Streams: Adding functionalities to streams, such as buffering or encryption, is done using
    decorators.

    View full-size slide

  32. In Real Applications…
    Adapter Pattern:
    Adapter for Legacy Code: When integrating new code with legacy systems, adapters are used to make the
    new code compatible with the old.
    Observer Pattern:
    Event Handling: In GUI frameworks, like Java Swing, observers are used for responding to user events like
    button clicks.
    MVC (Model-View-Controller) Pattern:
    Web Applications: MVC is widely used in web development, where the model represents data, the view
    displays it, and the controller manages user interactions.
    Proxy Pattern:
    Lazy Loading of Images: In a web application, images can be loaded lazily using proxy objects to improve
    performance by loading images only when needed.
    Dependency Injection Pattern:
    Spring Framework: Dependency injection is used extensively to manage and inject dependencies in Java-
    based applications, improving modularity and testability.

    View full-size slide

  33. Read more…
    Click to see the
    reference

    View full-size slide

  34. Thank You…
    Any Questions?
    nishanc.com/contact
    Test
    your
    knowledge
    © 2023 Design Patterns For Developers by Nishan Wickramarathna is
    licensed under CC BY 4.0

    View full-size slide