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
  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
  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
  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).
  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).
  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).
  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
  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
  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
  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
  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.
  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.
  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.
  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.
  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.
  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.
  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.
  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.
  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.
  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.
  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.
  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.
  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.
  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.
  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).
  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.
  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.
  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.
  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.
  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.
  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.
  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.
  33. 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