User Tools

Site Tools


notes:misc:software_patterns

Software Patterns

A design pattern is a general solution to a common software design problem.

Common Patterns

Pattern's purpose Pattern
Creational Patterns
Encapsulates a group of related factories. Abstract Factory
Separates a complex object's construction from its representation. Builder
Provides a generalized way to create instances of an object. Factory Method
Specifies an instance of a class that can be cloned to produce new objects. Prototype
- Ensures a class has only one instance.
- Provides a global point of access to the single instance.
Singleton
Structural Patterns
- Converts the interface of one class into another interface.
- Resolves incompatible interfaces.
- Provides a one-to-one mapping of a new class to an existing one.
Adapter
- Decouples an abstraction from its implementation so that both can be changed independently.
- Simplifies class hierarchy.
Bridge
Represents leaves and branches in a tree structure the same way. Composite
Adds functionality to an existing object by wrapping it and exposing the same interface as the existing object. Decorator (aka Wrapper)
- Provides a unified higher-level interface to a set of interfaces in a subsystem.
- Provides a simplified interface to a large collection of classes.
Facade
- Reduces storage costs for large number of objects.
- Uses sharing to support large numbers of fine-grained objects efficiently.
Flyweight
- Provides a surrogate or placeholder for another object to control access to it.
- Provides a one-to-one mapping of a new class to an existing one.
Proxy
Behavioral Patterns
Gives more than one receiver object a chance to handle a request from a sender object. Chain of Responsibility
- Encapsulates a request as an object.
- An object-oriented replacement for callbacks.
Command
Specifies how to represent and evaluate sentences in a language. Interpreter
Loops through elements of a collection or a sequence. Iterator
Defines an object that encapsulates how a set of objects interact. Mediator
Captures an object's internal state so that it can be restored to the same state later. Memento
- Allows a one-to-many notification of state changes between objects.
- Allows an object to receive a notification when a process completes or a state changes.
- Reduces direct dependencies between classes.
Observer
- Makes an object behave in distinct ways based on a current mode or state.
- Allows an object to appear to change its type when its internal state changes.
State
- Defines a family of algorithms, encapsulates each one, and makes them interchangeable at run-time.
- Decouples algorithm implementation from a class.
Strategy
Defines the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method
Represents an operation to be performed on the elements of an object structure. Visitor
Other Patterns and Techniques
Provides CRUD and/or CQRS (Command Query Responsibility Separation). Repository
Helps to create loosely coupled code. Dependency Injection

Dependency Injection

Dependency injection is a technique where an object is passed into a class (injected) instead of having the class create and store the object itself [Reddy 2011]

  • The primary purpose of dependency injection is to create loosely coupled code.
  • Dependency injection delegates the creation of services that an object consumes outside of the object.
  • The consumer does not have to decide which implementation to use. It only specifies interfaces to types it needs.
  • A container maps concrete types to interfaces, for example a FileDataService type may be mapped to IDataService.
  • The container creates instances of classes.
  • If an instance requires further dependecies (instances of other classes), the container will create them. This way the container resolves all dependencies in the chain of dependencies.

Constructor injection

  • Pass a dependency into a dependent class via constructor.
public class MainViewModel
{
    private IDataService dataService;
 
    public MainViewModel(IDataService dataService)
    {
        this.dataService= dataService;
    }
}

Property injection

  • Create a setter on the dependent class.
  • Use the setter to set the dependency.
  • Also called setter injection.
  • (+) You can change the dependency during run-time.
  • (-) You may try to use the object before a dependency is injected.

Example: You may want to assign a different DataService before calling the DataService's getter:

public class PersonRepository : IPersonRepository
{
    private IDataService dataService;
    public IDataService DataService
    {
        get
        {
            if (dataService == null)
                dataService = new FileDataService(); // a default repository
            return dataService;
        }
        set { dataService = value; }
    }
}

Interface injection

  • It is similar to the property injection. It uses a method rather than a property to do the injection.

Dependency injection frameworks

  • Unity
  • Autofac
  • Ninject
  • StructureMap
  • Castle.Windsor
  • Spring.NET

Repository

  • It is a low level layer that retrieves data from a WS or a DB. It abstracts details of data access.
  • Provides CRUD operations on models.
  • Provides caching if necessary.
  • Works with a single model or a family of related models (for example Invoices and InvoiceLines).
  • Returns model instances.
  • It may have a base class. The base class may, for example, create a connection to DB.
  • Implements an IRepository interface.

Related to the Repository is DataService:

  • Provides unit of functionality by combining calls to different repositories, for example a UserRepository and an InvoiceRepository.
  • Applies business rules (rather than implementing them in VM).
  • Implements an IDataService interface.

Adapter

  • Converts the interface of a class into another interface clients expect.
  • Allows classes to work together that couldn't otherwise due to incompatible interfaces.
  • Future-proof client implementations by having them depend on Adapter interfaces, rather than concrete classes directly.
  • May sit between the client code and a library.
  • The client calls the adapter operations on an Adapter's instance. It is assumed that the client knows the Adapter's interface.

Decorator (aka Wrapper)

  • Extends functionality of an existing object dynamically at runtime. You can use dependency injection to pass the exiting object to the decorator.
  • Supports the Open/Close Principle: the decorated classes are open for extensions but closed for modifications.

How it works:

  • Component is a base class or an interface.
  • ConcreteComponent inherits from Component. It is a class we want to add functionality to.
  • Decorator inherits from Component. It contains a private member of type Component which represents an object being decorated.
  • Pass the Component you want to wrap in the Decorator's ctor.
  • Decorator is a base class for all ConcreteDecorators.
  • ConcreteDecorators inherit from Decorator.
  • ctor accepts Decorator as an arg and passes it to the base class's ctor i.e., Decorator.

Examples of usage:

  • Adding functionality to legacy systems.
  • Adding functionality to UI controls
    • XAML's ScrollViewer is a decorator - it adds the scrolling functionality to any child control.
    • XAML's ContentControl is a decorator - it adds control-like behaviour (e.g., double-click) to non-control elements such as a Grid or Image.
  • Adding functionality to sealed classes.

Singleton

  • Enforces that only one instance of the class can be created.
  • Provides control over the allocation and destruction of the object.
  • Allows support for thread-safe access to the object's global state.
  • Useful for modelling singular resources such as the clipboard or the keyboard.
  • Useful for creating manager classes that provide a single point of access to multiple resources, such as a thread manager or an event manager.
  • Introduces global state and dependencies making your code difficult to unit test.
  • Consider introducing a “session” or “execution context” object that would hold all of the state rather than representing the state with multiple singletons.

An implementation of the singleton pattern in C#:

public class MySingleton
{
    // Let the CLR manage locking, mutex, and volatile stuff.
    private static readonly MySingleton instance = new MySingleton();
 
    // An empty static ctor determines that the class will be initialized before its first use.
    static MySingleton() {}
 
    private MySingleton()
    {
        //...
    }
 
    public static MySingleton Instance { get { return instance; } }
 
    //...
}

Chain of Responsibility

  • Sender is aware of only one receiver.
  • Each receiver is only aware of the next receiver.
  • Receivers process the message or send it down the chain.
  • The sender does not know who received the message.
  • The first receiver to handle the message terminates the chain.
  • The order of the receiver list matters.

Composite

  • Represent leaves and branches in a tree structure the same way. This way there is no distiction between the two.
  • Leaves and branches implement the same interface (Component interface).
  • We can traverse the entire tree automatically by invoking the interface method(s) on its root. It does not matter how many levels the tree has.

Flyweight

  • Reduces storage costs for large number of objects.
  • Stores state as intrinsic state and extrinsic state.
    • intrinsic state: stored in an object; does not depend on the context; it's shareable.
    • extrinsic state: supplied from outside; depends on the context.
  • Uses a factory to create flyweight instances. The factory maintans a pool of flyweights of various types.
  • Flyweight instances do not maintain identity i.e., you are not able to refer to specific flyweight instances.

.NET uses the flyweight pattern for string interning: keeping only one copy of the same string despite of being assigned to different string variables. You can force interning by using the String.Intern method.

Leaf objects in a hierarchy maintained using the Composite pattern are often flyweights.

Tester / Doer

Tester tests if the operation is legal; returns true or false. Doer performs the operation. Tester / doer pattern is not thread-safe.

notes/misc/software_patterns.txt · Last modified: 2018/06/22 by leszek