Designing with Patterns Workshop
Designing with Patterns
Agenda
-
Understand the role of intent in design patterns.
-
Use Decorators to avoid hierarchy explosion.
-
Use Proxies to serve as sophisticated references.
-
Use Iterators to provide sequential access to the elements of a collection.
-
Use Chain of Responsibility to delegate along a linked list of objects.
-
Use Strategies to pass algorithms to objects.
-
Use Commands to pass requests to objects.
-
Use Event Generators for asynchronous notification.
-
Use the Composite Pattern to treat objects and collections of objects uniformly.
-
Use Factories to delegate the production of objects.
-
Use Template Methods to delegate to subclasses.
Intent in Design Patterns
- Guideline: Understand the role of intent in design patterns.
- Many design patterns are composition for a purpose
- Instead of HAS-A: ADAPTS-A, DECORATES-A, PROXIES-A, ...
- Inheritance shows up primarily to get at polymorphism, not code reuse
- Delegation is all over the place
Adapter Pattern
- Composition with a purpose:
To grant existing code access to existing objects
- A very implementationy pattern
- Demonstrates interfaces in a composition relationship need not be compatible
State Pattern
- Composition with a purpose:
Refactor one big confusing class into many smaller, easier-to-understand classes
- Inheritance is for polymorphism, so front-end can switch between back-ends
- Purely an implementation decision
- Highlights: state machines, flyweights, objects as understandable units
- State classes are pure implementation --> small concept --> class extension
Discussion
- Guideline: Understand the role of intent in design patterns.
Decorator Pattern
- Composition with a purpose, again
- Inheritance is for polymorphism, so client can use many combinations of wrapped objects
- An interfacey pattern
- Highlights: IS-A is necessary but not sufficient, can modify composition relationships at run-time
- Account is exposed in the API --> large concept --> interface implementation
Discussion
- Guideline: Use decorators to avoid hierarchy explosion.
Proxy Pattern
- Composition with a purpose:
To serve as a sophisticated reference
- Protection proxy: controls access to back-end object
- Remote proxy: grant access to back-end in different VM
- Virtual proxy: performs lazy creation of expensive back-ends
- Decorator: client wraps back-ends itself
- Proxy: provider wraps back-end, passes only front-end to clients
- Inheritance used for polymorphism, so front-end can be used by client instead of back-end
Discussion
- Guideline: Use proxies to serve as sophisticated references.
Iterator Pattern
-
Composition with a purpose:
To provide sequential access to the elements of a collection
- Iterator: Provided by collection on request
- Note that inner classes are a language short-cut for composition
- Interitance used for polymorphism, so client can use the front-end iterator
Discussion
- Guideline: Use Iterators to provide sequential access to the elements of a collection.
Chain of Responsibility Pattern
- Composition with a purpose:
To delegate along a linked list of objects until one takes responsibility
- Interitance used for polymorphism, so each object in chain can delegate to the next
Discussion
- Guideline: Use Chain of Responsibility to delegate along a linked list of objects.
Strategy Pattern
- Composition with a purpose:
To pass algorithms to objects
- Strategy: back-end passed to front-end by client
- Another example: layout managers
- Interitance used for polymorphism, so front-end can invoke the algorithm
Discussion
- Guideline: Use Strategies to pass algorithms to objects.
Command Pattern
- Composition with a purpose:
To pass requests to objects
- Command: like Strategy, back-end passed to front-end by client
- Strategy: back-end is an algorithm that front end uses
Command: back-end is an action that front-end performs
- Front-end can queue up requests, store histories to support undo
- Interitance used for polymorphism, so front-end can execute the request
Discussion
- Guideline: Use Commands to pass requests to objects.
Observer Pattern
- Composition with a purpose:
For asynchronous notification
- Back-end passed to front-end by client
- Front-end notifies back-end listeners of events
- Interitance used for polymorphism, so front-end can notify listeners
Discussion
- Guideline: Use Event Generators for asynchronous notification.
Composite Pattern
- Composition with a purpose:
To treat objects and collections of objects uniformly
- Client builds tree structure by passing back-ends to front-ends
- Interitance used for polymorphism, so collection of back-ends can be treated as a back-end
Discussion
- Guideline: Use the Composite Pattern to treat objects and collections of objects uniformly.
Factory Pattern
- Delegation with a purpose:
To delegate the production of objects
- Static:
Has0State
's method getState
enforces single instance
- Instance: Service UI factory methods produce UI objects
- Inheritance used (in instance case) for polymorphism, so client can ask factory object
to create or provide the product object
Discussion
- Guideline: Use Factories to delegate the production of objects.
Template Method Pattern
- Inheritance with a purpose:
To delegate to subclasses
- By inheriting an superclass method implementation, the subclass delegates to the superclass
- Template method allows you to delegate to subclasses
- In composition, really delegating to back-end class, or even back-end programmer
Discussion
- Guideline: Use Template Methods to delegate to subclasses.