I. GRASP: More Patterns for Assigning Responsibilities (Larman, Chapter 22) A. new patterns, context ------------------------------------------ PREVIOUS GRASP PATTERNS FOR RESPONSIBILITY ASSIGNMENT Earlier patterns: - Information Expert - Creator - High-Cohesion - Low Coupling - Controller New Patterns: - Polymorphism - Indirection - Pure Fabrication - Protected Variations ------------------------------------------ B. Polymorphism (22.1) ------------------------------------------ POLYMORPHISM Solution: when behaviors or executions vary by type, assign responsibility for the variations to these types, using dynamic dispatch (virtual functions). Record the common parts in a supertype. Problem: How to handle different types of objects with similar, but not identical behavior? How to create pluggable components? ------------------------------------------ what's the problem with if-then-else's to handle different types? ------------------------------------------ Example: support different tax calculators |------------------| | <> | | TaxCalcAdapter | |------------------| |------------------| | getTaxes | | (Reservation): | | List of TaxLine | |------------------| /_\ | . |- - - - - - - - - - -| . . | | |------------------| |------------------| | SuperTaxCalc | | EZTaxesCalculator| | Adapter | | Adapter | |------------------| |------------------| | | | | |------------------| |------------------| | getTaxes | | getTaxes | | (Reservation): | | (Reservation): | | List of TaxLine | | List of TaxLine | |------------------| |------------------| ------------------------------------------ Where did the if-then-else go? C. pure fabrication (22.2) ------------------------------------------ PURE FABRICATION Solution: use a made-up class, not in the problem domain Problem: how to assign responsibility when using other patterns would violate high cohesion and low coupling, or other goals? Example: Need to save reservations persistently. Why not let Reservation do that? - lots of database specific knowledge it doesn't have ==> low cohesion - coupling to DBMS classes ==> hurts reuse - different kind of responsibility So ------------------------------------------ how does this solve the problems with having Reservation save themselves persistently? D. indirection (22.3) ------------------------------------------ INDIRECTION (22.3) Solution: assign responsibility to an intermediary to avoid coupling other components and services. The intermediary creates an indirection between the other components. Problem: how to de-couple objects so that they can change independently? How to avoid direct coupling? Examples: PersistentStorage is an intermediary between Reservation and the DBMS. TaxCalculatorAdapter is an intermediary between system and external tax calculators. ------------------------------------------ What are the benefits? E. Protected Variations (22.4) ------------------------------------------ PROTECTED VARIATIONS Solution: Assign responsibility to a stable interface that hides predicted instability Record the stable responsibilities in the interface. Problem: How to isolate changes or variations? Examples: Tax calculation variations Marketing gimmicks change prices ------------------------------------------ How is this done in automobile design? In medicine? ------------------------------------------ Discussion: - Very old principle of design - Movivates lots of mechanisms: - abstract data types, encapsulation - templates (generic polymorphism) - polymorphism (subtype polymorphism) LSP, supertype abstraction - data-driven designs - service lookup - interpreters, virtual machines - reflective/meta-level designs - uniform access to arrays, methods, fields - structure-hiding designs Law of Demeter: should only send to - this (or self) - a parameter - an attribute of this, - an element of a collection contained in "this" - an object freshly created ------------------------------------------ ------------------------------------------ Contraindications: Def: a *variation point* is a difference that must be supported in the current system. Def: an *evolution point* is a difference that may arise in the future, but is not present in existing requirements. Be realistic and only protect evolution points that are likely and expensive to change. ------------------------------------------ What are the benefits?