Aspect-Oriented Programming Gregor Kiczales University of British Columbia © Copyright 2004, Gregor Kiczales. All rights reserved.
CASCON Contents What is AOP How AOP works What AOP does for code and designs What’s happening with AOP today
CASCON Consider developing… a simple drawing application (JHotDraw)
CASCON Intuitively thinking of objects? Points, Lines… Drawing surfaces GUI Widgets … Display 2 Point getX() getY() setX(int) setY(int) moveBy(int, int) Line getP1() getP2() setP1(Point) setP2(Point) moveBy(int, int) Shape moveBy(int, int) *
CASCON most programmers would have used this has poor design and code modularity! collection of procedures to operate on and manage table entries In 1969…
CASCON What is OOP? a learned intuitive way of thinking design concepts –objects, classification hierarchies supporting mechanisms –classes, encapsulation, polymorphism… allows us to –make code look like the design –improves design and code modularity many other benefits build on these
CASCON class Point extends Shape { private int x = 0, y = 0; int getX() { return x; } int getY() { return y; } void setX(int x) { this.x = x; display.update(this); } void setY(int y) { this.y = y; display.update(this); } fair design modularity but poor code modularity 1 Display 2 Point getX() getY() setX(int) setY(int) moveBy(int, int) Line getP1() getP2() setP1(Point) setP2(Point) moveBy(int, int) Shape moveBy(int, int) * But some concerns “don’t fit” i.e. a simple Observer pattern
CASCON aspect ObserverPattern { private Display Shape.display; pointcut change(): call(void figures.Point.setX(int)) || call(void Point.setY(int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)) || call(void Shape.moveBy(int, int)); after(Shape s) returning: change() && target(s) { s.display.update(); } } ObserverPattern 1 Display 2 Point getX() getY() setX(int) setY(int) moveBy(int, int) Line getP1() getP2() setP1(Point) setP2(Point) moveBy(int, int) Shape moveBy(int, int) * With AOP they do fit good design modularity good code modularity
CASCON aspect ObserverPattern { private Display Shape.display; pointcut change(): call(void Shape.moveBy(int, int)) || call(void Shape+.set*(..)); after(Shape s) returning: change() && target(s) { s.display.update(); } } ObserverPattern 1 Display 2 Point getX() getY() setX(int) setY(int) moveBy(int, int) Line getP1() getP2() setP1(Point) setP2(Point) moveBy(int, int) Shape moveBy(int, int) * Ask yourself: could you name a single class “ObserverPattern” ? Code looks like the design
CASCON What is AOP? a learned intuitive way of thinking design concepts –aspects, crosscutting structure supporting mechanisms –join points, pointcuts, advice… allows us to –make code look like the design –improve design and code modularity
CASCON Today, We All Intuitively See Display 2 Point getX() getY() setX(int) setY(int) moveBy(int, int) Line getP1() getP2() setP1(Point) setP2(Point) moveBy(int, int) Shape makePoint(..) makeLine(..) moveBy(int, int) *
CASCON Today, We All Intuitively See operations that change shapes factory methods Display 2 Point getX() getY() setX(int) setY(int) moveBy(int, int) Line getP1() getP2() setP1(Point) setP2(Point) moveBy(int, int) Shape makePoint(..) makeLine(..) moveBy(int, int) *
CASCON AOP Developers Intuitively See… Display 2 Point getX() getY() setX(int) setY(int) moveBy(int, int) Line getP1() getP2() setP1(Point) setP2(Point) moveBy(int, int) Shape makePoint(..) makeLine(..) moveBy(int, int) * FactoryEnforcement ObserverPattern BoundsChecking
CASCON Mini-outline – next 15 minutes Explain how this AOP code works –Using AspectJ, leading AOP language Pointcuts-and-advice –dynamic join points, pointcuts, advice Inter-type declarations Multiple versions of ObserverPattern IDE demonstration Evaluating modularity –comparing AOP and non-AOP code
CASCON Method Execution Join Points :Point method execution join point the entry/exit to the execution not the source code setX(int)
CASCON More Method Execution Join Points :Lineend1:Point moveBy(int, int) setX(int) setY(int) moveBy(int, int) setX(int) setY(int) end2:Point
CASCON Method Call Join Points :Lineend1:Point moveBy(int, int) setX(int) setY(int) moveBy(int, int) setX(int) setY(int) end2:Point
CASCON Dynamic Join Points all dynamic join points on this slide are within the control flow of this dynamic join point :Lineend1:Point moveBy(int, int) setX(int) setY(int) moveBy(int, int) setX(int) setY(int) end2:Point well-defined points in flow of execution
CASCON execution(void Line.setP1(Point)) Pointcuts a pointcut is a predicate on dynamic join points that: –can match or not match any given join point –says “what is true” when the pointcut matches –can optionally expose some of the values at that join point a means of identifying dynamic join points matches method execution join points with this signature
CASCON Pointcut Composition whenever a Line executes a “void setP1(Point)” or “void setP2(Point)” method or a “void Line.setP2(Point)” execution a “void Line.setP1(Point)” execution execution(void Line.setP1(Point)) || execution(void Line.setP2(Point)); pointcuts compose like predicates, using &&, || and !
CASCON Primitive Pointcuts -call, execution -get, set -handler -initialization, staticinitialization -within, withincode -this, target, args -cflow, cflowbelow
CASCON User-Defined Pointcuts user-defined (aka named) pointcuts –can be used in the same way as primitive pointcuts defined with pointcut declaration pointcut change(): execution(void Line.setP1(Point)) || execution(void Line.setP2(Point)); nameparameters more on parameters and how pointcut can expose values at join points in a few slides
CASCON pointcut change(): execution(void Line.setP1(Point)) || execution(void Line.setP2(Point)); after() returning: change() { } After Advice a means of affecting semantics at dynamic join points :Line setP1(int) after advice runs on the way back out
CASCON A Simple Aspect an aspect defines a special class that can crosscut other classes ObserverPattern v1 box means complete running code aspect ObserverPattern { pointcut change(): execution(void Line.setP1(Point)) || execution(void Line.setP2(Point)); after() returning: change() { Display.update(); }
CASCON Pointcuts can cut across multiple classes pointcut change(): execution(void Line.setP1(Point)) || execution(void Line.setP2(Point)) || execution(void Point.setX(int)) || execution(void Point.setY(int));
CASCON Pointcuts can use interface signatures pointcut change(): execution(void Shape.moveBy(int, int)) || execution(void Line.setP1(Point)) || execution(void Line.setP2(Point)) || execution(void Point.setX(int)) || execution(void Point.setY(int));
CASCON A Multi-Class Aspect ObserverPattern v2 aspect ObserverPattern { pointcut change(): execution(void Shape.moveBy(int, int)) || execution(void Line.setP1(Point)) || execution(void Line.setP2(Point)) || execution(void Point.setX(int)) || execution(void Point.setY(int)); after() returning: change() { Display.update(); }
CASCON Using a Naming Convention ObserverPattern v2b aspect ObserverPattern { pointcut change(): execution(void Shape.moveBy(int, int)) || execution(void Shape+.set*(*)); after() returning: change() { Display.update(); }
CASCON pointcut change(Shape shape): this(shape) && (execution(void Shape.moveBy(int, int)) || execution(void Shape+.set*(*)); after(Shape s) returning: change(s) { } Values at Join Points pointcut can explicitly expose certain values advice can use explicitly exposed values demonstration, not detailed explanation parameter mechanism being used
CASCON Revised Aspect ObserverPattern v3 aspect ObserverPattern { pointcut change(Shape shape): this(shape) && (execution(void Shape.moveBy(int, int)) || execution(void Shape+.set*(*))); after(Shape s): change(s) { Display.update(s); }
CASCON aspect ObserverPattern { private Display Shape.display; static void setDisplay(Shape s, Display d) { s.display = d; } pointcut change(Shape shape): this(shape) && (execution(void Shape.moveBy(int, int)) || execution(void Shape+.set*(*))); after(Shape shape): change(shape) { shape.display.update(s); } One Display per Shape ObserverPattern v4 inter-type declarations declares members of other types –fields, methods
CASCON aspect ObserverPattern { private Display Shape.display; static void setDisplay(Shape s, Display d) { s.display = d; } pointcut change(Shape shape): this(shape) && (execution(void Shape.moveBy(int, int)) || execution(void Shape+.set*(*))); after(Shape shape): change(shape) { shape.display.update(s); } Aspect Can Own Object State ObserverPattern v4 display field –is in objects of type Shape –but belongs to ObserverPattern aspect –so ObserverPattern provide accessors private with respect to aspect
CASCON Field Getter/Setter aspect ObserverPattern { private Display Shape.display; static Display getDisplay(Shape s) { return s.display; } static void setDisplay(Shape s, Display d) { s.display = d; } … }... ObserverPattern.getDisplay(shape); ObserverPattern.setDisplay(shape, display); ObserverPattern v4
CASCON A 2 nd Join Point Model inter-type declarations –aka introductions –aka open classes for defining methods, fields join points –member declarations means of identifying join points –type patterns and signatures means of effecting join points –declare member
CASCON Aspect cuts new interface –through Point and Line DisplayUpdating itself is modular aspect ObserverPattern { private Display Shape.display; public void Shape.setDisplay(Display d) { this.display = d; } pointcut change(Shape shape): this(shape) && (execution(void Shape.moveBy(int, int) || execution(void Shape+.set*(*))); after(Shape s) returning: change(s) { Display.update(s); } Crosscutting Structure and Interfaces class Line { private Point p1, p2; Point getP1() { return p1; } Point getP2() { return p2; } void setP1(Point p1) { this.p1 = p1; } void setP2(Point p2) { this.p2 = p2; } class Point { private int x = 0, y = 0; int getX() { return x; } int getY() { return y; } void setX(int x) { this.x = x; } void setY(int y) { this.y = y; }
CASCON IDE support AJDT (AspectJ Development Tool) An Eclipse Project Goal is JDT-quality AspectJ support –highlighting, completion, wizards… –structure browser immediate outline overview
CASCON Modularity Assessment Use a simple evolution scenario
CASCON Without AspectJ class Line extends Shape { private Point p1, p2; Point getP1() { return p1; } Point getP2() { return p2; } void setP1(Point p1) { this.p1 = p1; } void setP2(Point p2) { this.p2 = p2; } class Point extends Shape { private int x = 0, y = 0; int getX() { return x; } int getY() { return y; } void setX(int x) { this.x = x; } void setY(int y) { this.y = y; }
CASCON class Line extends Shape { private Point p1, p2; Point getP1() { return p1; } Point getP2() { return p2; } void setP1(Point p1) { this.p1 = p1; Display.update(); } void setP2(Point p2) { this.p2 = p2; Display.update(); } class Point extends Shape { private int x = 0, y = 0; int getX() { return x; } int getY() { return y; } void setX(int x) { this.x = x; } void setY(int y) { this.y = y; } Without AspectJ ObserverPattern v1
CASCON class Line extends Shape { private Point p1, p2; Point getP1() { return p1; } Point getP2() { return p2; } void setP1(Point p1) { this.p1 = p1; Display.update(); } void setP2(Point p2) { this.p2 = p2; Display.update(); } class Point extends Shape { private int x = 0, y = 0; int getX() { return x; } int getY() { return y; } void setX(int x) { this.x = x; Display.update(); } void setY(int y) { this.y = y; Display.update(); } Without AspectJ ObserverPattern v2
CASCON Without AspectJ ObserverPattern v3 class Line extends Shape { private Point p1, p2; Point getP1() { return p1; } Point getP2() { return p2; } void setP1(Point p1) { this.p1 = p1; Display.update(this); } void setP2(Point p2) { this.p2 = p2; Display.update(this); } class Point extends Shape { private int x = 0, y = 0; int getX() { return x; } int getY() { return y; } void setX(int x) { this.x = x; Display.update(this); } void setY(int y) { this.y = y; Display.update(this); }
CASCON class Shape { private Display display; abstract void moveBy(int, int); } class Line extends Shape { private Point p1, p2; Point getP1() { return p1; } Point getP2() { return p2; } void setP1(Point p1) { this.p1 = p1; Display.update(this); } void setP2(Point p2) { this.p2 = p2; Display.update(this); } class Point extends Shape {... } Without AspectJ “display updating” is not modular –evolution is cumbersome –changes are scattered –have to track & change all callers –it is harder to think about ObserverPattern v4
CASCON With AspectJ class Line extends Shape { private Point p1, p2; Point getP1() { return p1; } Point getP2() { return p2; } void setP1(Point p1) { this.p1 = p1; } void setP2(Point p2) { this.p2 = p2; } class Point extends Shape { private int x = 0, y = 0; int getX() { return x; } int getY() { return y; } void setX(int x) { this.x = x; } void setY(int y) { this.y = y; }
CASCON With AspectJ aspect ObserverPattern { pointcut change(): execution(void Line.setP1(Point)) || execution(void Line.setP2(Point)); after() returning: change() { Display.update(); } ObserverPattern v1 class Line extends Shape { private Point p1, p2; Point getP1() { return p1; } Point getP2() { return p2; } void setP1(Point p1) { this.p1 = p1; } void setP2(Point p2) { this.p2 = p2; } class Point extends Shape { private int x = 0, y = 0; int getX() { return x; } int getY() { return y; } void setX(int x) { this.x = x; } void setY(int y) { this.y = y; }
CASCON With AspectJ ObserverPattern v2 aspect ObserverPattern { pointcut change(): execution(void Shape.moveBy(int, int) || execution(void Line.setP1(Point)) || execution(void Line.setP2(Point)) || execution(void Point.setX(int)) || execution(void Point.setY(int)); after() returning: change() { Display.update(); } class Line extends Shape { private Point p1, p2; Point getP1() { return p1; } Point getP2() { return p2; } void setP1(Point p1) { this.p1 = p1; } void setP2(Point p2) { this.p2 = p2; } class Point extends Shape { private int x = 0, y = 0; int getX() { return x; } int getY() { return y; } void setX(int x) { this.x = x; } void setY(int y) { this.y = y; }
CASCON With AspectJ ObserverPattern v2.5 aspect ObserverPattern { pointcut change(): execution(void Shape.moveBy(int, int) || execution(void Shape+.set*(*)); after() returning: change() { Display.update(); } class Line extends Shape { private Point p1, p2; Point getP1() { return p1; } Point getP2() { return p2; } void setP1(Point p1) { this.p1 = p1; } void setP2(Point p2) { this.p2 = p2; } class Point extends Shape { private int x = 0, y = 0; int getX() { return x; } int getY() { return y; } void setX(int x) { this.x = x; } void setY(int y) { this.y = y; }
CASCON aspect ObserverPattern { pointcut change(Shape shape): this(shape) && (execution(void Shape.moveBy(int, int) || execution(void Shape+.set*(*))); after(Shape s) returning: change(s) { Display.update(s); } With AspectJ ObserverPattern v3 class Line extends Shape { private Point p1, p2; Point getP1() { return p1; } Point getP2() { return p2; } void setP1(Point p1) { this.p1 = p1; } void setP2(Point p2) { this.p2 = p2; } class Point extends Shape { private int x = 0, y = 0; int getX() { return x; } int getY() { return y; } void setX(int x) { this.x = x; } void setY(int y) { this.y = y; }
CASCON ObserverPattern is modular –all changes in single aspect –evolution is modular –it is easier to think about With AspectJ ObserverPattern v4 class Line extends Shape { private Point p1, p2; Point getP1() { return p1; } Point getP2() { return p2; } void setP1(Point p1) { this.p1 = p1; } void setP2(Point p2) { this.p2 = p2; } class Point extends Shape { private int x = 0, y = 0; int getX() { return x; } int getY() { return y; } void setX(int x) { this.x = x; } void setY(int y) { this.y = y; } aspect ObserverPattern { private Display Shape.display; static void setDisplay(Shape s, Display d) { s.display = d; } pointcut change(Shape shape): this(shape) && (execution(void Shape.moveBy(int, int)) || execution(void Shape+.set*(*))); after(Shape shape): change(shape) { shape.display.update(s); }
CASCON Modularity Assessment The aspect is –localized –has a clear interface The classes are –better localized (no invasion of updating) Code modularity helps design modularity –simple observer pattern is simple The code looks like the design Forest vs. trees –the crosscutting structure is explicit, clear, modular –the local effects can be made clear by IDE
CASCON Review So Far Aspect is a software design concept –supported by mechanisms –a “learned intuitive way of thinking” Mechanisms –Pointcuts and advice dynamic join points, pointcuts, advice –Inter-type declarations Different concepts for different structure of concerns –procedure holds computeRadius, setX… –class holds Point, Line… –aspect holds ObserverPattern… Aspects –modular units of implementation –look like modular units of design –improves design and code
CASCON Dynamic Join Points several kinds of dynamic join points –method & constructor execution –method & constructor call –field get & set –exception handler execution –static & dynamic initialization method call method execution :Point setX(int) well-defined points in flow of execution
CASCON Only Top-Level Changes ObserverPattern v5 aspect ObserverPattern { pointcut change(Shape shape): this(shape) && (execution(void Shape.moveBy(int, int)) || execution(void Line.setP1(Point)) || execution(void Line.setP2(Point)) || execution(void Point.setX(int)) || execution(void Point.setY(int))); pointcut topLevelchange(Shape s): change(s) && !cflowbelow(change(Shape)); after(Shape shape) returning: topLevelchange(shape) { Display.update(shape); }
CASCON Pre-conditions using before advice aspect BoundsPreConditionChecking { before(int newX): execution(void Point.setX(int)) && args(newX) { check(newX >= MIN_X); check(newX <= MAX_X); } before(int newY): execution(void Point.setY(int)) && args(newY) { check(newY >= MIN_Y); check(newY <= MAX_Y); } private void check(boolean v) { if ( !v ) throw new RuntimeException(); } what follows the ‘:’ is always a pointcut – primitive or user-defined
CASCON Design Invariants aspect FactoryEnforcement { pointcut newShape(): call(Shape+.new(..)); pointcut inFactory(): within(Point Shape.make*(..)); pointcut illegalNewShape(): newShape() && !inFactory(); before(): illegalNewShape() { throw new RuntimeError("Must call factory method…“); } Display 2 Point getX() getY() setX(int) setY(int) moveBy(int, int) Line getP1() getP2() setP1(Point) setP2(Point) moveBy(int, int) Shape makePoint(..) makeLine(..) moveBy(int, int) *
CASCON Design Invariants aspect FactoryEnforcement { pointcut newShape(): call(Shape+.new(..)); pointcut inFactory(): within(Point Shape.make*(..)); pointcut illegalNewShape(): newShape() && !inFactory(); declare error: illegalNewShape(): "Must call factory method to create figure elements."; } Display 2 Point getX() getY() setX(int) setY(int) moveBy(int, int) Line getP1() getP2() setP1(Point) setP2(Point) moveBy(int, int) Shape makePoint(..) makeLine(..) moveBy(int, int) *
CASCON Property-Based Pointcuts Consider code maintenance Another programmer adds a public method i.e. extends public interface – this code will still work Another programmer reads this code “what’s really going on” is explicit aspect PublicErrorLogging { Log log = new Log(); pointcut publicInterface(): call(public * com.acme..*.*(..)); after() throwing (Error e): publicInterface() { log.write(e); } neatly captures public interface of mypackage
CASCON Swing Thread Safety [Laddad ’03] public abstract aspect SwingThreadSafetyAspect { abstract pointcut uiMethodCall(); pointcut threadSafeCall(): call(void JComponent.revalidate()) || call(void JComponent.repaint(..)) || call(void add*Listener(EventListener)) || call(void remove*Listener(EventListener)); pointcut excludedJoinPoint(): threadSafeCall() || within(SwingThreadSafetyAspect+) || if(EventQueue.isDispatchThread()); Object around() : uiMethodCall() && !excludedJoinPoint() { /* run in another thread… */ } }
CASCON Reusable Patterns abstract aspect ObserverPattern { protected interface Subject { } protected interface Observer { } public void addObserver(Subject s, Observer o) {... } public void removeObserver(Subject s, Observer o) {... } public List getObservers(Subject s) {... } abstract pointcut change(Subject s); after(Subject s): change(s) { Iterator iter = getObservers(s).iterator(); while ( iter.hasNext() ) { notifyObserver(s, ((Observer)iter.next())); } abstract void notifyObserver(Subject s, Observer o); } [Hanneman OOPSLA’02]
CASCON Concrete Reuse aspect DisplayUpdating extends ObserverPattern { declare parents: FigureElement implements Subject; declare parents: Display implements Observer; pointcut change(Subject s): target(s) && (call(void FigureElement.moveBy(int, int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)) || call(void Point.setX(int)) || call(void Point.setY(int))); void notifyObserver(Subject s, Observer o) { ((Display)o).update(s); } [Hanneman OOPSLA’02]
CASCON vm_fault vm_pager_getpages vnode_pager_getpages ffs_getpages … ufs_bmap Path Specific Customization ffs_valid ffs_calc_size [Coady AOSD’03]
CASCON Other Aspects Security –pointcut for when checking happens –makes invariant clear, enforced Optimization Distribution Synchronization Persistence and of course, Logging –IBM story and very many application-specific aspects –i.e. EnsureLiveness
CASCON Benefits of AOP All the usual modularity benefits –clarity –reusability –quality –easier to develop –configuration management –product line management –IP management –testing –…
CASCON Use Cases Each use case is realized by a collaboration - a set of classes A class plays different roles in different use case realizations The total responsibility of a class is the composition of these roles Withdraw Cash Deposit Funds Transfer Funds Cash Withdrawal Cash Interface Cash Interface Deposit Funds Transfer Funds Interface Funds Deposit Cash Transfer Funds Cash Withdrawal Use case Specification Use case design Component design & implementation
CASCON More Existing Crosscutting join points –method call reception return aStateChange() _aStateChange() notify() update() SubjectObserver
CASCON Industry Adoption AOP adoption is happening very fast Enterprise Java is most active domain –AspectWerkz, JBoss (JavaAssist), Spring, … –IBM actively using AspectJ in Websphere … –BEA, Oracle actively evaluating –Hot topic at TSS Symposium and JavaOne And this year… –Danny Sabbah (IBM VP) commits to AOP in 3 of 5 main product lines –Gates says Microsoft will adopt AOP
CASCON Summary AOP is a learned intuitive way of thinking –aspects, crosscutting structure Supporting mechanisms –join points, pointcuts, advice, inter-type declarations Allows us to –make code look like the design –improve design and code modularity A practical way to improve your –software designs, code, product, productivity
CASCON Composition Patterns [Clarke, Walker] AOP support in UML Subject + addObserver(Object) + removeObserver(Object) + aStateChange(..) # _aStateChange(..) - notify() subjects * Vector observers 1 Observer + update() + start(..,Subject,..) # _start(..,Subject,..) + stop(..,Subject,..) # _stop(..,Subject,..) «subject» Observer
CASCON Aspect Enabled Refactoring Mockup
CASCON Fluid Aspects
CASCON Fluid Aspects
CASCON All Kinds of Crosscutting aStateChange() _aStateChange() notify() update() SubjectObserver
CASCON pointcut entry(): !within(com.acme.product..*) && call(public * com.acme.product..*(..)); pointcut initialEntry(): entry() && !cflowbelow(entry()); around(): initialEntry() { proceed(); } Compositional Crosscutting package structure wrt control flow
CASCON Limits of Current JP Mechanisms but –if you add a new field for color –you have to extend this pointcut so… after(): call(void Point.setX(int)) || call(void Point.setY(int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)) || call(void FigureElement.moveBy(int, int)) { Display.update(); } it is still it is better than without AOP the dependence is explicit, localized, modular & clear declarative interface (the structure of the crosscutting concern is explicit)
CASCON A More Powerful Pointcut robust against some edits the abstraction of the pointcut is now more clear but –if you add a field that doesn’t have a set method –you still have to update the pointcut so… –you could solve this problem by prohibiting wildcards? –you could solve this problem by requiring tags on methods? –NO! solve it by making the means of identifying JPs more precise after(): call(void FigureElement+.set*(..)) || call(void FigureElement.moveBy(int, int)) { Display.update(); }
CASCON A More Semantic Pointcut predict the control flow of FigureElement.draw() sets to such fields require display update find fields referenced in that control flow pointcut* displayState(): pcflow(execution(void FigureElement+.draw()) && get(* FigElt+.*); after set( ) (): { Display.update(); }
CASCON Other More Semantic Pointcuts dflow(, ) –did the value of the variable come in a dataflow through [Masuhara 04] min(, ) –the least common caller of the two cflows JP mechanism opens a new design space –a language design for packaging such analyses –how to think about programming with them –how to limit to tractable cases
CASCON Observer Subject Observer: Display change update: {...} class Point { int x; Getter/Setter int y; void draw() { Graphics.drawOval(…); }... } Superposition of Patterns and Code pattern must be effective (connect to code) ‘wizards’ weave the pattern in but what happens if code changes?
CASCON Observer Subject Observer: Display change update: {...} class Point { int x; Getter/Setter int y; void draw() { Graphics.drawOval(…); }... } Making ‘Generators’ Work Together Observer can refer to expansion of Getter/Setter –clearly, reliably, stably –alternate reference, beyond causal reach, indexical multiple routes to reference beyond causal reach indexical
CASCON use pointcut to identify scattered aspect 2.shows up below 3.delete them all 4.rewrite with advice