Skip to content

Instantly share code, notes, and snippets.

@mikeyamadeo
Last active August 29, 2015 14:19
Show Gist options
  • Save mikeyamadeo/fa4650d5695a099ed3e4 to your computer and use it in GitHub Desktop.
Save mikeyamadeo/fa4650d5695a099ed3e4 to your computer and use it in GitHub Desktop.
Design & Testing Final

Pattern Problem Solution Example

##Pattern - Chain of responsibility Problem: Prototype delegation

##Pattern - Plugin Problem:

  • The functionality of a system needs to be extended after the software is shipped
  • The set of possible post-shipment extensions is large
  • Specific details on future extensions are not available, but their general nature is predictable
  • It should be possible to extend the system without access to the system's source code, by people who were not the system's original developers

It should be easy to add and remove extensions in whatever combination is desired by the customer ##Pattern - Strategy customize a class’s functionality with plug-in algorithms

##Pattern - Decorator Problem - Sometimes we need to be able to add functionality to an object in a flexible and dynamic way Don’t want to change the base functionality, just add to it

  • Window  Window with scrollbars

Solution -

interface Runner {
	void run();
}
class A implements Runner {
	void run() {
		System.out.println("A.run");
	}
}
class B implements Runner {
	Runner delegate;
	B(Runner delegate) {
		this.delegate = delegate;
	}
	void run() {
		System.out.println("B.run pre-processing");
		delegate.run();
		System.out.println("B.run post-processing");
	}
}
class C implements Runner {
	Runner delegate;
	C(Runner delegate) {
		this.delegate = delegate;
	}
	void run() {
		System.out.println("C.run pre-processing");
		delegate.run();
		System.out.println("C.run post-processing");
	}
}
//
// Client
//
Runner obj = new C(new B(newA()));
obj.run();

##Pattern - Adapter Problem - You have a class that does what you need, but the interface it supports is not the interface expected by the rest of the application.

Solution - You can write an "adapter" class to translate between the interface expected by clients, and the interface provided by the class.

##Reuse

  1. Forces against: What conditions must exist to make a class reusable? -Generality (customizable to the present need) -Performant (general without sacrificing performance) -Available across programming languages and operating systems -Easily obtainable (inexpensive or free, reasonable licensing, downloadable on web) -Well documented -Well supported and maintained -Source code available -Awareness (if I don’t know about it, I can’t use it) -Maturity and Humility (overcome NIH syndrome and the urge to do it myself)

  2. Forms of reuse -Binaries -Source code -Design patterns -Specifications -Requirements, Functional, Design -People -Knowledge and experience

##Template Method Pattern

/**
 * An abstract class that is common to several games in
 * which players play against the others, but only one is
 * playing at a given time.
 */
 
abstract class Game {
 
    protected int playersCount;
    abstract void initializeGame();
    abstract void makePlay(int player);
    abstract boolean endOfGame();
    abstract void printWinner();
 
    /* A template method : */
    public final void playOneGame(int playersCount) {
        this.playersCount = playersCount;
        initializeGame();
        int j = 0;
        while (!endOfGame()) {
            makePlay(j);
            j = (j + 1) % playersCount;
        }
        printWinner();
    }
}
//Now we can extend this class in order 
//to implement actual games:
 
class Monopoly extends Game {
 
    /* Implementation of necessary concrete methods */
    void initializeGame() {
        // Initialize players
        // Initialize money
    }
    void makePlay(int player) {
        // Process one turn of player
    }
    boolean endOfGame() {
        // Return true if game is over 
        // according to Monopoly rules
    }
    void printWinner() {
        // Display who won
    }
    /* Specific declarations for the Monopoly game. */
 
    // ...
}

##Inheritance, composition, & specialization Inheritance:

  • With inheritance, changes to A are more likely to break B than with composition
  • Supports polymorphism, while composition does not

Composition:

  • Client class creates an internal instance of existing class and invokes its functionality through regular method calls
  • More flexible than inheritance
  • Leads to lower coupling than inheritance
  • Allows control over which delegate features are exposed, and what the API looks like
  • Composition relationships can be changed at runtime (more flexible than inheritance)

Specialization: A “specialization” of a class is a subset of its instances that have even more properties and operations in common

class Animal {
  type
}
class Dog {

}
class GermanSheperd extends Dog {

}
  • "has a" -> composition
  • "uses a" -> composition
  • "is-a" -> inheritance

Exceptions:

  • (Dynamic “is-a” relationships should be implemented using composition). i.e person who can change vocation. An engineer is a person but what if he becomes a lawyer?
  • Multi-valued “is-a” relationships should also be implemented using composition. User who can be a dev manager & tester

##Inheritance DBC #####DBC:

  • If a client invokes an operation having satisfied all pre-conditions, the supplier must ensure that all post-conditions are met upon return
  • If the client did not satisfy all pre-conditions, the supplier is under no obligation to satisfy the postconditions

####Class Invariant A class invariant is simply a property that holds for all instances of a class, always, no matter what other code does. X has the class invariant that there is a y property and it is never null and it has a value of type Y

######Rules

  1. B’s behavior must be consistent with A’s contract
  2. B can provide a “better” implementation than A, but not a “worse” one
  3. B can be less strict on clients than A, but not more strict. B can weaken R’s pre-conditions
  4. B can strengthen R’s post-conditions, but not weaken
  5. B can strengthen A’s class invariants, but not weaken
class Stack {

	/**
	 * Inserts a new value into the stack
	 * 
	 * @param value Value being inserted
	 * 
	 * @pre !isFull()
	 * @pre value != null
	 * 
	 * @post !isEmpty()
	 * @post top() == value
	 * @post size() == old(size()) + 1
	 */
	public void push(Object value) {
		...
	}

}

////////////////////////////////////
// Subclass that violates DBC rules
////////////////////////////////////

class StrangeStack extends Stack {


	/**
	 * Inserts a new value into the stack
	 * 
	 * @param value Value being inserted
	 * 
	 * @pre !isFull()
	 * @pre value != null
	 * @pre value instanceof String
	 * @pre value.length() <= 50
	 * 
	 * @post !isEmpty()
	 * @post top() == UPPERCASE(value)
	 * @post size() == old(size()) + 1
	 */
	public void push(Object value) {
		...
	}

}

/////////////////////////////////////
// Subclass that satisfies DBC rules
/////////////////////////////////////


class MiracleStack extends Stack {

	/**
	 * Inserts a new value into the stack
	 * 
	 * @param value Value being inserted
	 * 
	 * @pre !isFull()
	 * 
	 * @post !isEmpty()
	 * @post top() == value
	 * @post size() == old(size()) + 1
	 * @post a loaf of freshly baked bread awaits you at home
	 */
	public void push(Object value) {
		...
	}

}

##Pattern - Abstract Factory Problem - Provide an interface for creating families of related or dependent objects without specifying their concrete classes

Solution - Abstract factories declare an interface for operations that create abstract objects and then concrete factories implement those operations

consequences - isolates clients from implementation & makes exchanging implementations simple

Example -

  buildHouse() {
    buildRoof(),
    placeDoor(),
    tileKitchen()
  }
  
  var giantHouse = Object.create(buildHouse);
  giantHouse.

##Refractoring What: A series of small steps, each of which changes the program’s internal structure without changing its external behavior

Methods: link

  • Extract method
  • Replace Temp with Query
  • Move method
  • Replace Type Code with State / Strategy
  • Replace conditional with polymorphism
  • Form Template Method

Bad Smells:

  • Duplicated code
  • Long method
  • Large class
  • Long parameter list
  • Divergent change
  • Shotgun surgery
  • Feature envy
  • Data clumps
  • Primitive obsession
  • Switch statements
  • Parallel inheritance hierarchies
  • Lazy class
  • Speculative generality
  • Temporary field
  • Message chains
  • Middle man
  • Inappropriate intimacy
  • Alternative classes with different interfaces
  • Incomplete library class
  • Data class
  • Refused bequest
  • Comments

##Pattern - Command

Problem - Sometimes a class needs to perform actions without knowing what the actions are

Solution - package commands to be executable at any given time

Example - good for undo/redo


##Pattern - Visitor

Problem - Code for each operation (typeCheck(), optimize(), generateCode()) of an abstract syntax tree is distributed across many node classes so adding new operation requires modifying every node class.

Solution - All code for an operation is on one class so adding a new operation doesn not require changes to the node classes Example:

function node(val) {
this.value = val;
this.left = this.right = null;
}

var tree = new node("A");
tree.left = new node("B1");
tree.right = new node("B2");
tree.left.left = new node("C1");
tree.left.right = new node("C2");

node.prototype.accept = function(visitorObj) {
    visitorObj.visit(this);
    if (this.left) this.left.accept(visitorObj);
    if (this.right) this.right.accept(visitorObj);
}

function visitor() {
    var that = this;
    this.visit = function(tgt) {
        tgt.value = "*"+tgt.value;
    }
    this.highlight = function(tgt) {
        tgt.accept(that);
    }
}

(new visitor()).highlight(tree.left);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment