I. Template Method (design patterns book, p. 325 ff., Larman section 34.12) A. motivation 1. frameworks (34.3) ------------------------------------------ FRAMEWORKS (34.3) Definition: a *framework* is an extendable set of classes with related functions. It has: - a cohesive set of interfaces and classes - many abstract classes to be subclassed - relies on the *Hollywood principle* "don't call us, we'll call you" E.g., Java AWT, Java Swing, C++ Interviews ------------------------------------------ 2. requirements for persistence service framework (34.4) ------------------------------------------ REQUIREMENTS (34.4) Provide functions such as: - store and retrieve objects in a persistent storage mechanism - commit and rollback transactions Support different storage mechanisms and formats (RDBMS, XML, ...) CONCEPTS Transactions: preserving consistency, by making sure each operation happens completely or not all Object identity: objects have a unique identity that must be preserved ------------------------------------------ 3. key implementation ideas (34.5) ------------------------------------------ KEY IMPLEMENTATION IDEAS (34.5) materialization persistent ----------------> internal storage <---------------- objects dematerialization Caches: avoid I/O if possible ------------------------------------------ 4. representing objects as tables (34.6) ------------------------------------------ REPRESENTING OBJECTS AS TABLES (34.6) public class City { private String name; } --> CITY TABLE |-------------- | name | |-------------- | "Mumbai" | | "San Ramon" | | ... | |-------------- ------------------------------------------ What kinds of problems arise from this type of modeling? 5. pattern: object identifier (34.8) ------------------------------------------ OBJECT IDENTIFIERS (34.8) public class City { private String name; private OID oid; City(OID oid, String name) { this.oid = oid; this.name = name; } } --> CITY TABLE |----------------------- | OID | name | |----------------------- | manf34 | "Mumbai" | | manf35 | "San Ramon" | | ... | ... | |----------------------- ------------------------------------------ 6. accessing the persistence service within a facade (34.9) 7. Mapping Objects: Database Mapper (Broker) pattern (34.10) B. Materialization with the Template method Pattern (34.12) ------------------------------------------ BASIC DESIGN FOR MATERIALIZATION if (object not in cache) { create from external rep save in cache } return object in cache What parts change among different kinds of persistent storage mechanisms? ------------------------------------------ ------------------------------------------ TEMPLATE METHOD import java.util.Hashtable; public abstract class AbstractMapper implements IMapper { public final Object get(OID oid) { Object obj = cachedObjects.get(oid); if (obj == null) { // call hook method obj = getFromStorage(oid); cachedObjects.put(oid, obj); } return obj; } // hook method protected abstract Object getFromStorage(OID oid); private Hashtable cachedObjects = new Hashtable(); public final void put(OID oid, Object o) { putToStorage(oid, o); } protected abstract void putToStorage(OID oid, Object o); } ------------------------------------------ ------------------------------------------ CONCRETE SUBCLASS EXAMPLE import java.sql.*; public class CityRDBMapper extends AbstractMapper implements DBAccountConsts { protected Object getFromStorage(OID oid) { try { String key = oid.toString(); String url = "jdbc:odbc:reservsys"; Connection con = DriverManager.getConnection( url, USERNAME, PASSWORD); Statement stmt = con.createStatement(); ResultSet dbRec = stmt.executeQuery( "Select * from FLIGHT where key =" + key); String name = dbRec.getString("NAME"); City c = new City(oid, name); return c; } catch (SQLException se) { return null; } } protected void putToStorage( OID oid, Object o) { // ... } } ------------------------------------------ Would any of this could be common between different subclasses of AbstractMapper? 1. discussion In what way that the template method pattern limit how subclasses behave? In what way does the template method pattern satisfy the "Hollywood principle"? Why should the hook method be declared protected in the superclass? Can a superclass provide default behavior for a hook method? ------------------------------------------ WHY NOT DO IT THIS WAY? public class Parent { public void operation() { // ... } } public class Child extends Parent { public void operation() { // extensions to behavior ... super.operation(); // possibly other extensions ... } } ------------------------------------------ 2. other examples 3. related patterns C. more about persistence 1. synchronized or guarded methods 2. creating the mappers (34.13) How would you create all of these mapper classes? How would you protect against variation in the number of classes to be mapped to the persistent storage? 3. cache management (34.14) II. State (design patterns book, p. 305 ff., Larman section 34.16) A. motivation B. problem ------------------------------------------ PROBLEM MOTIVATING THE STATE PATTERN public class PeristentObject { private OID oid; private DateTime timeStamp; private int state; public void commit() { switch (state) { case OLD_DIRTY: // ... break; case OLD_CLEAN: // ... break; } } public void rollback() { } } ------------------------------------------ What would the code for rollback look like? C. solution ------------------------------------------ Problem: how to avoid repeating code to interpret state transitions Soluton: create an interface for states, and subclasses for each particular state. ------------------------------------------ D. example ------------------------------------------ EXAMPLE public class PeristentObject { private OID oid; private DateTime timeStamp; private PObjState state; public void commit() { state.commit(this); } public void delete() { state.delete(this); } public void rollback() { state.rollback(this); } public void save() { } protected void setState(PObjState s) { state = s; } } ------------------------------------------ How does the save method body get filled in? ------------------------------------------ public class PObjState { public void commit(PersistentObject o) { } public void delete(PersistentObject o) { } public void rollback(PersistentObject o) { } public void save(PersistentObject o) { } } public class OldDirtyState { private static instance; private OldDirtyState() {} public static synchronized OldDirtyState getInstance() { if (instance == null) { instance = new OldDirtyState(); } return instance; } public void commit(PersistentObject o) { PersistenceFacade.getInstance() .update(o); o.setState( OldCleanState.getInstance()); } public void rollback(PersistentObject o) { PersistenceFacade.getInstance() .reload(o); o.setState( OldCleanState.getInstance()); } public void delete(PersistentObject o) { o.setState( OldDeleteState.getInstance()); } } ------------------------------------------ How would you code OldCleanState? NewState? OldDeleteState? E. discussion 1. applicability 2. benefits 3. related patterns III. Command (design patterns book, p. 233ff, Larman section 34.17) A. motivation What happens if the system crashes during this operation? B. problem ------------------------------------------ COMMAND PATTERN (34.17) Problem: How to: - create, queue, and execute requests at different times, - support undo, - support logging to reapply changes after a crash - parameterized objects by an action to perform (e.g., menus) Solution: make each task a class that implements a common interface. ------------------------------------------ C. example ------------------------------------------ import java.util.*; public Transaction { private List commands; public void addDelete(PersistentObject o) { commands.add(new DBDeleteCommand(o); } public void addInsert(PersistentObject o) { commands.add(new DBInsertCommand(o); } public void addUpdate(PersistentObject o) { commands.add(new DBUpdateCommand(o); } public void commit() { sort(); Iterator i = commands.iterator(); while (i.hasNext()) { (ICommand)(i.next()).execute(); } } public void sort() { // ... } } ------------------------------------------ ------------------------------------------ public interface ICommand { void execute(); void undo(); } public abstract class DBCommand implements ICommand { protected PersistentObject object; } public class DBUpdateCommand extends DBCommand { DBUpdateCommand(PersistentObject o) { po = o; } public execute() { po.commit(); } } public class DBInsertCommand extends DBCommand { DBInsertCommand(PersistentObject o) { po = o; } public execute() { po.commit(); } } public class DBDeleteCommand extends DBCommand { DBDeleteCommand(PersistentObject o) { po = o; } public execute() { po.commit(); } } ------------------------------------------ D. discussion 1. execution 2. other examples 3. consequences 4. implementation 5. related patterns E. visitor (design patterns book, p. 331ff) IV. Decorator (design patterns book, p. 175 ff)