- The intention of this guide is to be succinct. Don't use this for extended explanation, just note brief points. People can follow links for explanation.
- While this guide may be useful for the exam, don't be exam specific. This is a concise list of concepts to jog your memory, not a Cheat Sheet with direct answers from last year or whatever.
Contradictory Design Maxims
- Design by contract and Tell, don't ask (arguably)
- Composite pattern and Avoid no-op overrides
- Eliminate irrelevant classes and No concrete base classes
- The visitor pattern and the acyclic dependencies principle
- Visitor and Hide data within its class,Tell, don't ask
- Observer and Tell, don't ask
Related Design Maxims
- Dependency inversion principle and Program to the interface not the implementation and Design by contract
- Open closed principle and Liskov substitution principle and Design by contract
- Open closed principle and Common closure principle
- Avoid side effects and Command query separation and Keep accessors and mutators separate
- One key abstraction and Separation of concerns and Keep related data and behavior in one place and Single responsibility principle
- Avoid inheritance for implementation and Favor composition over inheritance
- Software reuse and Reusable frameworks over reusable components
- Minimize accesses to variables and Getters and Setters
- Make all Member Variables Private and Avoid protected data
- No Global Variables and Singleton
- Defer identification of state variables pattern and Intelligent children pattern and Define classes by behavior, not state pattern
- Law of demeter and Tell, don't ask
Johnson and Foote Related Maxims
- Recursion introduction
- If classes and component classes have a recursive-style relationship (eg car.start() calls engine.start(), then give them the same/similar names)
- Class hierarchies should be deep and narrow
- Riel #5.4: Favour deep hierarchies, with proviso of Riel #5.5: Limit hierarchy depth
- Separate methods that do not communicate
- Separation of concerns, One key abstraction, etc, etc (see above section)
Performance-Focussed Maxims (as opposed to the usual design-focus)
Design Pattern Cliff Notes
- Identify by: Both HAS A and IS A at the same time, with multiple subclasses.
- Used for: Adding flexible combinations of specialized functionality.
- Classic Example: Adding scrolling functionality, borders, etc to a window.
- Why better than alternatives: Avoids combinatorial explosion of subclasses.
- Identify by: Both HAS A and IS A at the same time, usually without subclasses.
- Used for: Making many act as one.
- Classic Example: Making a shape comprising other shapes.
- Why better than alternatives: Can use singular and collective instances totally transparently (identically).
- Identify by: Private constructor. Accompanying static "public Whatever getWhatever" method, with that method containing lazy initialization of the (static) return value.
- Used for: Ensuring only a single instance is ever created.
- Classic Example: Providing a single global Factory object or Settings object.
- ** Why better than alternatives: No need to pass around many references. Prevents unwanted duplicates. Lazy initialization. Tidier than plain global variables,
- Disadvantage: Hard to refactor, might indicate a design problem. See Beware singletons.
- Identify by: Factory class which returns objects from a pool of pre-existing instances, instead of creating a new instance every time.
- Used for: Avoiding memory overhead of creating a multitude of identical objects.
- Classic Example: Letter objects in a word processing application, tokens in State machine design
- Why better than alternatives: Space saving (identical instances reference the same instance in memory)
- Disadvantage: Because of the reference reuse, identity tests won't work as expected (eg Java object1==object2)
- Identify by: Subclass with reference to sibling class. The subclass provides lazy initialization of the sibling class.
- Used for: Creating an instance when you don't want to use that instance immediately. Can also be used to provide a reduced subset of the original object's interface.
- Classic Example: Anything "on-demand". Diagramming program, creating instances of all components of the diagram when most are initially offscreen.
- Why better than alternatives: Performance saving, as "grunt-work" is only carried out when actually needed. Can use proxy instances and real instances totally transparently.
- Identify by: There are two variants.
- Object-based adapters: A subclass that makes use of a toolkit/library class to implement its functionality
- Class-based adapters: Multiple inheritance. A subclass inherits from one superclass in the usual way, and also inherits from another superclass to make use of that superclass's functionality
- Used for: Making a useful-but-incompatible class work with an existing interface.
- Classic Example: TextGraphics toolkit class allows you to render text, so is useful, but doesn't have the same interface as your existing graphical object class.
- Why better than alternatives: Enables great reuse without modifying existing interfaces and code.
- Identify by: There are two variants.
- Identify by: Two hierarchies, one providing abstractions, the other providing implementations.
- Used for: Decoupling interface from implementation so each can vary independently
- Classic Example: Multiplatform GUIs, with a hierarchy of window types, each of which uses a subclassed hierarchy of drawing operations (with one subclass per platform)
- Why better than alternatives: Avoids the multiplicity of subclasses (FancyWindowsWindow, BasicWindowsWindow, FancyMacWindow, BasicMacWindow, etc etc). Conforms to Dependency inversion principle.
- Identify by: Abstract-style superclass with an interface used to building individual components; implemented by subclasses. Related class which uses aforementioned abstract class to build objects transparently.
- Used for: Build complex objects in a transparent way.
- Classic Example: Text conversion. If an original document is stored as HTML, use a builder subclass for each type we need to convert to (ASCII, RTF, etc). Each subclass implements the abstract convertTagBlock() method. Converted document instance is retrieved from Builder object at the end.
- Why better than alternatives: Allows fine external control over the building process while maintaining flexibility/extensibility/transparency.
- Identify by: An abstract syntax tree used for parsing.
- Used for: Parsing.
- Classic Example: Parsing.
- Why better than alternatives: Intuitive, as each token is represented as an object.
- Identify by: An abstract class to represent Commands/Actions
- Used for: The OO equivalent of callbacks. Representing commands as objects allows commands to be transparently executed.
- Classic Example: Menu Items. To assign functionality, simply add a Command object to a MenuItem object.
- Why better than alternatives: Can make Composite commands from primitive commands. Total decoupling between triggering an action and the implementation of that action.
Similar Design Patterns
- Strategy, State, Bridge have the same structure. The difference is in the implementation.
- Strategy generally only implements one algorithm for the different behaviours and therefore the ConcreteStragey objects just implement one of the Strategy's methods.
- State generally has more information such as fields about the containing object plus one or more methods.
- Bridge is very similar to State but is more to do with an abstraction storing different implementations.
- Factory Method, Abstract Factory
- Abstract Factory is a family of related Factory Methods.