parkerjgit
7/18/2018 - 5:38 AM

_resources.md

Strategy Pattern (or Policy Pattern)


[TOC]


Strategy pattern enables selection or composition, of algorithms, i.e. strategies, at runtime.

The strategy pattern defines a family of algorithms, encapsulates each algorithm, and makes the algorithms interchangeable within that family. Strategy lets the algorithm vary independently from clients that use it. (Wikipedia)

Strategy pattern is a response to the limitations and overuse of inheritance and interfaces.

see see Understanding the pitfalls of inheritance and interfaces

Related to Principle: Encapsulate code that varies over time.

see Programming Foundations: Desin Patterns

Related to Principle: Favor composition over inheritence.

see Programming Foundations: Desin Patterns

Related to Principle: Design to interface not implementation (for the code that varies anyways).

see Programming Foundations: Desin Patterns

Examples


Singleton


Features/Intent
  • Ensures that one and only one object of the class gets created
  • Provides global access to a shared object
  • lazy creation to ensures object is not created until it is needed.
Issues/Tradeoffs
Java Implementation:

Make the constructor private and create a public static method that returns the single private static instance of the class if it exists. Otherwise, lazily creates a new instance and returns it.

class Singleton {
    private static Singleton instance;
    private Singleton() {...}
    public static Singleton getlnstance () { 
        if (instance == null) {
            instance = new Singleton(); 
        }
        return instance; 
    } 
}
  • lazy creation ensures object is not created until it is really needed.
Python Implementation:

There are no private constructors in python, so we could make the whole singleton class "private" and wrap it in a another class of the same name that is responsible for controling creation of an instance and assigning it to a class property __instance.

class OnlyOne(object):

    class __OnlyOne: ...
    __instance = None

    def __new__(cls): # __new__ always a classmethod
        if not OnlyOne.__instance:
            OnlyOne.instance = OnlyOne.__OnlyOne()
        return OnlyOne.__instance

    def __getattr__(self, name):
        return getattr(self.instance, name)

    def __setattr__(self, name):
        return setattr(self.instance, name)

(based on The Singletone)

Concise Python implementation

A more concise version simply checks whether a class instance already exists. If it doesn't, then create one before returning it. Otherwise just return it.

class Singleton(object):
    def __new__(cls):
        if not hasattr(cls, 'instance'):
            cls.instance = super(Singleton, cls).__new__(cls)
        return cls.instance
Python implementation with lazy instantiation

But, if we want lazy instantiation, then we must move object creation to a static getInstance() method as we did with the Java implementation.

class Singleton:

    __instance = None  

    def __init__(self): pass

    @classmethod
    def getInstance(cls):
        if not cls.__instance:
            cls.__instance = Singleton()
        return cls.__instance

(Giridhar 84)

Observer Pattern (vs. Pub/Sub)


[TOC]


Strategy pattern enables selection or composition, of algorithms, i.e. strategies, at runtime.

The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods... It is mainly used to implement distributed event handling systems, in "event driven" software... is also a key part in the familiar model–view–controller (MVC) architectural pattern.

Related to design principle: Strive for loosely coupling between objects that interact.

see also The Advantages of loose coupling

use pub/sub for even looser coupling.

Python implementation

class Observable:
    def __init__(self):
        self.__observers = []
    
    def register_observer(self, observer):
        self.__observers.append(observer)
    
    def notify_observers(self, *args, **kwargs):
        for observer in self.__observers:
            observer.notify(self, *args, **kwargs)

class Observer:
    def __init__(self, observable):
        observable.register_observer(self)
    
    def notify(self, observable, *args, **kwargs):
        print('Got', args, kwargs, 'From', observable)


subject = Observable()
observer = Observer(subject)
subject.notify_observers('test')

(adapted from Observer pattern)

Note, the absence of persistant state in this simple example. Observer pattern is being used to pass values to registered observers rather than notify state change!

Two types of implementations: push and pull

With push, the subject notifies th observer that ists data is ready and includes the relevant info that the observer is subscribing to, whereas with the pull design, it is the observer's job to retrieve the info from the subject.

Pull places heavier load on the observers, allows observer to qu3ery only when data is actually needed, ie., on-demain access. This however, requires that observers have public access to subject, and risks pulling data in the middle of an update.

Push is more common b/c simpler and safer. Data and data transfer in subject's control and there is no need to worry about observer pulling data during update.

see EPI

Unlike Pub/Sub, the the observer pattern sets up direct communication between subject and observer, i.e. more tightly coupled.

Pub/Sub mediator, typically provided by third-party library, sits between publisher and subscribers and mediates communication, such that neither knows about the other: Publisher makes a broadcast and mediating logic routes to everyone listening. This, effects a decoupling. Conversely, Subjects are passed a reference to each observer that registers with it, maintains a list of registered observers, and notifies them directly of any state changes (in the case of push implementation), usually by calling one of their methods! In the case of a pull implementation, subject and observer are even more tightly coupled, as observers are granted public access to the subject's data!

https://channel9.msdn.com/Shows/Visual-Studio-Toolbox/Design-Patterns-Observer-and-Publish-Subscribe

See also Publisher/Subscriber pattern with Event/Delegate and EventAggregator. As far as I can tell, Event/Delegate is a C# implementation of observer pattern as we have defined it above (though they call it publisher/subscriber), and EventAggregator is an implementation of what we are calling pub/sub, where there is a mediating class (EventAggregator), that sits between publisher and subscribers.

Use weak reference to avoid memory leaks

Design Pattern Resources

Videos/Courses

Texts

http://python-3-patterns-idioms-test.readthedocs.io

Giridhar, Chetan. Learning Python Design Patterns: Leverage the Power of Python Design Patterns to Solve Real-World Problems in Software Architecture and Design. 2016.

(Giridhar xxx)

Creational Patterns