Skip to content

Instantly share code, notes, and snippets.

@christiearcus
Last active September 16, 2016 02:03
Show Gist options
  • Save christiearcus/e9b4d0cb9705bf45e472298b739fd41f to your computer and use it in GitHub Desktop.
Save christiearcus/e9b4d0cb9705bf45e472298b739fd41f to your computer and use it in GitHub Desktop.
Design Patterns Course Lynda.com

Decorator Pattern

The decorator pattern attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for extending functionality.

Aims to avoid 'class chaos'. Uses open / closed principle. Add new behaviour, but without implementing regression. Uses delegation and composition.

The 'component' is the abstract thing, and the decorators are the concrete things that implement it. Any decorator should be able to be wrapped to any abstract component.

Example

Abstract Component

class Beverage {

  constructor() {
    this.description = "unknown beverage"
  }
  
  getDescription() {
    return description;
  }
  
  getCost() {
    return cost;
  }
}
class HouseBlend extends Beverage {
  constructor() {
    this.description = "House Blend Coffee";
  }
  
  cost() {
    return .89;
  }
}
class Espresso extends Beverage {
  constructor() {
    this.description = "Espresso";
  }
  
  cost() {
    return 1.99;
  }
}
class Milk extends CondimentDecorator {
  constructor() {
    this.beverage = beverage
  }
  
  getDescription() {
    return beverage.getDescription() + ", Milk";
  }
  
  cost() {
    return .10 + beverage.cost()
  }
}

Decorating time!

  const beverageOne = new Espresso();
  beverageOne.getDescription();
  beverageOne.getCost();
  // doesn't need any decorating.
  
  const beverageTwo = new HouseBlend();
  beverageTwo = new Milk(beverageTwo);
  beverageTwo.getDescription();
  // => blah blah + milk.
  beverageTwo.getCost();
  // => milk + house blend cost added together.

Design Principles

Here are some design principles that are common in the Strategy pattern. Not to be confused with design patterns themselves!

  1. Encapsulate what varies.
  2. Program to an interface.
  3. Favour composition over inheritence.
  4. Strive for loosely coupled designs between objects that interact.
  5. Classes should be open for extension, but closed for modification.
  6. A class should only have one reason to change.

What is a design pattern? A solution to a problem in a context.

Intro

  • prerequisites: objects, abstraction, inheritance and polymorphism.
  • Revisit course after a few months to solidify learning.
  • Flexible and maintainable code.
  • Dealing with change.

History

  • Invented by four dudes. Twenty three design patterns. We will be focusing on 7 of these.
  • Not a module or library! A higher level than these, first need to understand then adapt to your code.
  • Shared vocabulary. Just use the observer pattern. Powerful.
  • Avoids miscommunications. Ultimate in reuse! Saves trial and error. Reusing experience.

Inheritence

  • Core to OO.
  • IS A - a cat shares from the feline class
  • overused.

Problems that can arise from inheritance are:

  1. Duplication of code between classes (sub-classes). Not getting the reuse benefits.
  2. Have to go in to each concrete class to see how it works.
  3. Changes on the super-class can affect the sub-classes (if a new feature request comes in).
  4. Runtime behaviour changes can be hard.

Observer Pattern

Defines a one to many dependency between objects, so that when one object changes state, all of it's dependents are notified and updated automatically.

Less abstract to explain than the strategy pattern. Publishers and Subscribers. Doesn't matter what objects make the request to subscribe.

Subject & Dependents. They observe and are notified of changes in state.

You can either push or pull data from subject to dependent (get or set).

  • This tutorial uses the java in-built observable classes.
  • Loosely coupled, so both sides can change / be replaced without the other caring.
  • Goal is to reduce dependency between subject and objects.

Singleton Pattern

The singleton pattern ensures a class has only once instance, and provides a global access point to it.

Uses where a resource / object only existing once is useful:

Connection and threads Logging facilities Device drivers UI dialog and modals

Why can't I just instantiate once?

Wouldn't is be as easy as new MySingleObject() ? But there's nothing about this that can enforce that this happens only once.

Preventing instantiation:

  • Private constructor.
  • Only able to call the constructor from inside the class.
  • one method on class getInstance().

Something like (not sure how it works in JS):

class Singleton {
  _constructor() {
    return uniqueInstance;
  }
  
  getInstance() {
    if (uniqueInstance === null) {
      uniqueInstance === new Singleton();
    }
    else {
      return uniqueInstance;
    }
  }
}

Issues / caveats with Singleton:

  • Unique threads both trying to instantiate! They'd all override each other. Syncronous only. Java has ways to handle this.
  • Performance concerns if you limit to syncronous thread.

Strategy Pattern

Defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

HAS A, instead of an IS A relationship.

HAS A is composition. A duck has a flyingBehaviour(). Duck is composed with this method (algorithm). IS A is inheritance. A duck inherits a flyingBehaviour() method from the super-class, which isn't flexible, and would need to be overridden in most cases for different ducks.

@christiearcus
Copy link
Author

Iterator / Collection Pattern

  • Designed to encapsulate iteration through collections.
  • Might have an array or object or any other type of collection. Instead of the client knowing about which collection type this is, have a middle class which can iterate through the different data types. This way the client doesn't have to know.

@christiearcus
Copy link
Author

Factory Pattern

  • Encapsulates creation, so that the client doesn't need to know which 'type' to instantiate in it's constructor. This will save heaps of conditional logic in your client class, and the factory can be responsible for handling updates / additions / subtractions of the different types of sub-class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment