Aspect Oriented Programming and Design - Presentation Transcript
Aspect-Oriented
Programming and Design
For Java and AspectJ
Dean Wampler
Object Mentor, Inc.
dean@objectmentor.com
Friday, September 7, 2007 1
public class Account {
public Money getBalance()
{...}
public void credit(Money m)
{...}
public void debit(Money m)
{...}
...
}
Friday, September 7, 2007 2
For example...
public void credit(Money m) {
balance += m;
}
Friday, September 7, 2007 3
Clean
and
Simple
Friday, September 7, 2007 4
However,
Real applications need:
Transactions
public class BankAccount {
public Money getBalance(){...}
public void credit(Money m) {...}
Persistence
public void debit(Money m) {...}
...
}
Security
Friday, September 7, 2007 5
Back to our example...
public void credit(Money m) {
if (unauthorized())
throw new ...();
Money saveBalance = balance;
try {
beginTransaction();
balance += m;
persistBalance(balance);
} ...
Friday, September 7, 2007 6
Back to our example...
public void credit(Money m) {
balance += m;
}
Back to what we want...
Friday, September 7, 2007 12
Back to our example...
class-like declaration
public aspect PersistentAccount{
pointcut newBalance ( bind variables
Account a, Money newBal):
set (Money Account.balance) &&
args (newBal) && this (a);
remember “this”
... named set of “join points”
remember new value
any time “balance” is set
Friday, September 7, 2007 13
Back to our example...
“after advice”
... same arguments
after (
Account a, Money newBal) :
same
newBalance(a, newBal) {
pointcut
persist(a, newBal);
}
body of the advice
Friday, September 7, 2007 14
Types of advice
before
after returning
after throwing
after
around
Friday, September 7, 2007 15
Other terms
• Join point
• Pointcut
• Advice
• Cross-cutting concern
• Introduction (a.k.a. Inter-type declaration)
• Aspect
Friday, September 7, 2007 16
Pure Java AOP
Spring AOP
JBoss AOP
Friday, September 7, 2007 17
Spring AOP
@AspectJ Support
Friday, September 7, 2007 18
auto-configure @Aspects
<aop:aspectj-autoproxy/>
...
<bean id=”persistantAccount”
class=”...PersistentAccount”>
<!-- properties of bean -->
</bean>
The usual Spring bean stuff...
Friday, September 7, 2007 20
<aop:config> Wire another advice
using XML
<aop:advisor
pointcut=\"....newBalance()\"
advice-ref=\"tx-advice\"/>
</aop:config>
<tx:advice id=\"tx-advice\">
<tx:attributes>
<tx:method name=\"*\"
propagation=\"REQUIRED\"/>
</tx:attributes>
</tx:advice>
Friday, September 7, 2007 21
Spring’s
Dependency Injection
can also wire
“POJO” aspects
Friday, September 7, 2007 22
Recommendation:
Use Spring to introduce AOP into your environment.
Friday, September 7, 2007 23
JBoss AOP works in
similar ways.
Friday, September 7, 2007 24
Aspect-Oriented Design
(Starting in the early years)
Friday, September 7, 2007 25
“Classes should be
oblivious to aspects.”
Friday, September 7, 2007 26
However, this leads to...
Friday, September 7, 2007 27
Persistence Aspect
PCD: set (* *.name)
X ???
Account Account
first_name
name
last_name
Version 1 Version 2
Friday, September 7, 2007 28
Aspects make initial version easier,
But subsequent versions harder!
Friday, September 7, 2007 29
!
AOP-Evolution
x
o
d
a
r
a
P
Friday, September 7, 2007 30
Obliviousness ...
... is like that.
Friday, September 7, 2007 31
We forgot
established
OOD
Principles.
Friday, September 7, 2007 32
11
Principles of
OOD
Friday, September 7, 2007 33
#1
Single Responsibility
Principle
A class should have only
one reason to change.
Friday, September 7, 2007 34
#2
Open-Closed
Principle
A module should be open
for extension, but closed
for modification.
Friday, September 7, 2007 35
An Example...
Friday, September 7, 2007 36
public interface Shape {
public double getArea();
public void draw();
}
Friday, September 7, 2007 37
public abstract class Polygon
implements Shape {
public Point getVertex(int index)
{...}
public void draw() {...}
public String toString() {...}
}
Friday, September 7, 2007 38
public class Square
extends Polygon {
public double getArea() {...}
}
public class Rectangle
extends Polygon {
public double getArea() {...}
}
Friday, September 7, 2007 39
Square is a Rectangle?
Isn’t it?
Friday, September 7, 2007 40
An Aspect Refactoring...
public interface Shape {
public double getArea();
public void draw();
}
Friday, September 7, 2007 41
public abstract class Polygon
implements Shape {
public Point getVertex(int index)
{...}
public void draw() {...}
public String toString() {...}
}
Friday, September 7, 2007 42
package shapes.tostring;
public aspect PolygonToString {
public String Polygon.toString()
{...}
}
Friday, September 7, 2007 43
package drawing;
public interface Drawable {
void draw();
}
Friday, September 7, 2007 44
#3
Liskov Substitution
Principle
Subtypes must be
substitutable for their
base types.
Friday, September 7, 2007 46
Square is a Rectangle?
What do the unit tests say?
Friday, September 7, 2007 47
public RectangleDrawTest {
extends ...
public void testDraw {
Shape[] shapes = new Shapes[] {
new Rectangle(...),
new Square(...)};
for (Shape s: shapes)
s.draw(); // just works...
}
}
Friday, September 7, 2007 48
Square is a Rectangle?
Apparently, it is!!
(at least in this context...)
Friday, September 7, 2007 49
Mutability...
Friday, September 7, 2007 50
Need to Change Polygon:
public abstract class Polygon
implements Shape {
public Point getVertex(int index)
{...}
List<Point> getVertices() {...}
}
Occasionally need to break OCP...
Package private!
Friday, September 7, 2007 51
package shapes; // same package
import ...;
aspect MutablePolygon {
public void
Polygon.setHeight(int i) {
List<Point> list = getVertices();
// Change appropriate points...
}
public void
Polygon.setWidth(int i) {...}
}
Friday, September 7, 2007 52
Square is a Rectangle?
Friday, September 7, 2007 53
public MutableRectangleTest ... {
public void testSetWidth{
Point p00, p20, p25, p05 = ...;
Rectangle rect =
new Rectangle(p00,p20,p25,p05);
(0,5) (2,5)
(0,0) (2,0)
Friday, September 7, 2007 54
public MutableRectangleTest ... {
public void testSetWidth{
Point p00, p20, p25, p05 = ...;
Rectangle r = new Rectangle
(p00,p20,p25,p05);
assertEquals(2, r.getWidth());
assertEquals(5, r.getHeight());
r.setWidth(3);
assertEquals(3, r.getWidth());
assertEquals(5, r.getHeight());
}
}
Friday, September 7, 2007 55
Square is a Rectangle?
Prove it! (or not...)
Friday, September 7, 2007 56
What if I Use a Square?
...
Rectangle r = new Square
(p00,p50,p55,p05);
assertEquals(5, r.getWidth());
assertEquals(5, r.getHeight());
r.setWidth(3);
assertEquals(3, r.getWidth());
assertEquals(5, r.getHeight());
This won’t pass!
Friday, September 7, 2007 57
Square is a Rectangle?
Not in
this context!!
Friday, September 7, 2007 58
LSP
Is
Context Dependent!
Friday, September 7, 2007 59
LSP Is the Basis for
Design by Contract
Friday, September 7, 2007 60
Shameless Plug...
Friday, September 7, 2007 61
Contract4J: DbC for Java
annotation-based
@Contract
public abstract class Polygon
implements Shape {
@Pre(“index>=0”)
@Post(“$return != null”)
public Point getVertex(int index)
{...}
}
Friday, September 7, 2007 62
#5
Dependency
Inversion Principle
Abstractions should not depend upon
details.
Details should depend upon
abstractions.
Friday, September 7, 2007 63
Client Service
Client
Service Service
Friday, September 7, 2007 64
Service
Client
Service
«aspect»
«aspect»
Client
Client
ClientService
ClientService
Service Service
Friday, September 7, 2007 65
New AOD Principles
Friday, September 7, 2007 66
package shapes.tostring;
public aspect PolygonToString {
public String Polygon.toString()
{...}
} Do introductions violate OCP??
No
Friday, September 7, 2007 67
Open-Closed
Principle: Updated
A module should be open for
extension, but closed for source
and contract modification.
Friday, September 7, 2007 68
public aspect Tracer {
before(): call(* Polygon.*(..)) {
log(thisJoinPointStaticPart);
}
Similar!
}
public class LoggedPolygonDraws {
public void draw() {
log(“Polygon.draw”);
super.draw();
}
}
Friday, September 7, 2007 69
Liskov Substitution
Principle: Updated
Subtypes and aspects + base
types must be substitutable for
their base types.
Friday, September 7, 2007 70
public aspect PolygonMunger {
before(Polygon p): target(p) &&
call(* Polygon.draw(..)) {
p.addPoint(new Point(/*...*/));
}
}
Does this look safe??
Friday, September 7, 2007 71
Advice Substitution
Principle
Advice must obey the contract of
the advised join point.
Friday, September 7, 2007 72
public aspect CirclingPolygons {
public double Polygon.getRadius()
{...}
public Point Polygon.getCenter()
{...}
}
Huh??
Friday, September 7, 2007 73
Introduction
Substitution Principle
Introductions must obey the
contract of the module.
Friday, September 7, 2007 74
public aspect PersistentAccount {
after (Account a): target(a) &&
call(* Account.setName()) {
persistName(a.getName());
}
}
What happens when “name” is refactored
to “firstName” and “lastName”??
Friday, September 7, 2007 75
Pointcut Inversion
Principle
Pointcuts should not depend upon
concrete details.
Pointcuts should depend upon
abstractions.
Friday, September 7, 2007 76
The Future of AOP
Friday, September 7, 2007 77
Components and
Frameworks
• Much hyped in the 90s
• All or nothing proposition
• ... due to internal dependencies
Can aspects reduce the coupling
and make them more reusable?
Friday, September 7, 2007 78
«aspect»
«aspect»
Client
Client
ClientService
ClientService
Service Service
Friday, September 7, 2007 79
Improved Architectures
• High-level defines policy
• Low-level defines details
Better separation using aspects?
Friday, September 7, 2007 80
Improved Architectures
• Domain-Specific Languages for the high-level
• Connect to low-level details with aspects
Friday, September 7, 2007 81
public class PersistenceDSL {
public PersistenceDSL() {
after()
.calling(methodsIn(
interface(StateChange.class)))
.then(persistChange());
}
}
(Fanciful, made-up example...)
Friday, September 7, 2007 82
Conclusions
Friday, September 7, 2007 83
Real applications...
mix multiple domains...
causing tangled code.
Friday, September 7, 2007 84
Objects alone don’t
prevent this tangling.
Friday, September 7, 2007 85
Aspects modularize the
intersection
of the domains.
Friday, September 7, 2007 86
0 comments
Post a comment