Understanding Design Pattern Density with Aspects A Case Study in JHotDraw with AspectJ Simon Denier, Pierre Cointe OBASCO Project École des Mines de Nantes / INRIA ETAPS SC 2006 1 1
What is Pattern Density? From “JUnit: a Cook's Tour”, Gamma & Beck Mature frameworks show a high density of patterns especially around key abstractions (TestCase in JUnit) because patterns provide leverage to extend the framework but they also make code harder to change (because of tangling) “easier to use, harder to change” What means “harder to change” exactly? 2 2
Density, Composition, and Aspects A high density most probably implies that some design patterns compose together Aspects enable modularization of crosscutting concerns Hannemann et al shows some new modular, reusable implementations of design patterns with AspectJ Intuition: better modularization by aspects could ease, or at least highlight, the composition of design patterns 3 3
Incremental Approach with JHotDraw JHotDraw: a framework for structured drawing a design exercise with several design patterns (high density of patterns around Figure, the key abstraction) Our incremental approach: isolate a base framework (more basic than the current one) enhance the base with functions involving design patterns have the option to come back to basic framework at no cost for example, by a selection of modules at compile-time Purpose: show the impact of design patterns composed together without/with aspects 4 4
Example: View observes Figures Purpose: Figures notify View when they change, in order to optimize redraw with their clipping area observer aView aDrawing notify figure1 figure2 figure3 subjects 5 5
Example: Observer aspect General case (multiple observers per subject) aspect FigureOberver { /* Structure by Inter-Type Declaration (ITD) */ private Vector Figure.observers = new Vector(); /* Registration */ pointcut registerObserver(Figure f, View v): (...) after(Figure f, View v): registerObserver(f, v){ f.observers.add(v); } /* Notification Points */ pointcut changed(Figure f): this(f) && execution(void Figure+.move(..)); /* Notification Process */ after(Figure f): changed(f) { for (int i = 0; i < f.observers.size(); i++) f.observers.elementAt(i).invalidate(f); } } 6 6
Single View vs Multiple Views 7 7
Singleton-Observer (1) Single view on drawing and figures Simplification of the Observer pattern when observer is a Singleton (global access) no structure to hold list of observers no registration of observer simple notification process View.instance().invalidate(f); Object impact: insert notification points in code Simple implementation, easy to understand, simple to use 8 8
Singleton-Observer (2) Multiple views on drawing and figures General case of Observer pattern Object impact: invasive modifications define list of observers in subjects insert (de)registration points for observers dispatch notification process Notification points: same as for Singleton Unfortunately, we have lost the simple collaboration with singleton view 9 9
Singleton-Observer with Aspects Observer pattern is modularized in one aspect Aspects can be easily plugged/unplugged Solution: provide two aspects, one general and one for the Singleton case selection by user based on current configuration of framework (single view or multiple views) Future work: automatic selection based on detection of Singleton? 10 10
Composite-Decorator and Observer Add GroupFigure (Composite) and BorderDecorator build tree of Figures under Drawing aView aDrawing aGroupFigure aBorderDecorator figure1 figure2 figure3 Problem: BorderDecorator modifies the clipping area of its underneath Figure the Figure knows when to notify the view must get the clipping area from the BorderDecorator 11 11
Object Solution: O + C-D → CoR + C-D Transform Observer into a Chain of Responsibility a Figure notify its parent in the hierarchy of figures, either a GroupFigure or a BorderDecorator the Drawing stops the recursive process and notifies the view(s) BorderDecorator can handle notifications from its child and modify them aView aDrawing * aGroupFigure aBorderDecorator figure1 figure2 figure3 12 12
Object Impact BorderDecorator and GroupFigure become both observers and subjects although GroupFigure is not primarely concerned View is involved to stop the recursive process All notifications must follow the chain 13 13
O + C-D with Aspects A change command defines a recursive control flow whenever it is sent down the tree of Figures use AspectJ pointcuts based on control flow (cflow) Only the Observer aspect is modified the impact is limited to pointcuts (contrary to the overall impact of Chain of Responsibility) Can we do better? Yes! different pointcuts on different actions = different strategies for notification (not just chained handling) 14 14
Top-Level Observer Notify only the top level action, because action necessarily triggers a change (example: move action) Simple (well-known) solution in AspectJ pointcut changed (Figure f): this(f) && execution(void Figure+.move(..)) && !cflowbelow(execution(void Figure+.move(..))) aView aDrawing aGroupFigure aBorderDecorator figure1 figure2 figure3 15 15
Path Observer (BorderDecorator) aView aDrawing aGroupFigure aBorderDecorator figure1 figure2 figure3 get top-most BorderDecorator (the one which defines the overall clipping area for the current action) pointcut topmost(Figure f): this(f) && execution(void Figure+.setAttribute(..)) && !cflowbelow(execution(void Figure+.setAttribute(..))) pass it on the underneath join point to replace the current Figure pointcut changed(Figure f): cflowbelow(topmost(f)) && execution(void Figure+.setAttribute(..)) 16 16
Impact of Pattern Density on Objects What is “harder to change”? Inner modification (Singleton-Observer) Broad transformation on a set of classes (Chain of Responsibility) Invasive impact, the basic solution is lost 17 17
Contributions of Aspects Impact limited to one module or simply pointcuts Adaptation is fine grained with pointcuts but has also a large scale (a control flow across many objects) allows reasoning on a large scale, even for small details Aspects provide better modularization between classes But the pointcut language is tailored to provide meaningful adaptation following class relationships (e.g. cflow) 18 18
Specificity of Aspects? cflow constructs can be emulated if we have an inspector on the execution stack Inter-type declaration is akin to mixin inheritance or traits So nothing specific, but well integrated into aspects Why not integrate other mechanisms into language? seek for expressiveness on common design pattern structure: recursivity, indirection 19 19
Questions? 20 20
Recommend
More recommend