> to ajoo
> 这个网址分别使用了Java和AspectJ实现GoF设计模式,从对比
> 校阋残砜煞⑾AOP独特的优势,我没仔细看,如果你看了有
> 裁聪敕ǎ黄鹛致郏?>
> http://www.cs.ubc.ca/~jan/AODPs/
>
> to noxel:
> 我刚拉了Spring框架,在研究中,看了架构设计,感觉复杂罗
> 铝说悖岬EJB也是若即若离,没有明显特征....

to banq:
spring 本身包含了太多非IOC的东东,如,又一个mvc 框架,对hibernate,ibitas的封装,对ejb的封装,等等。不象pico那么纯洁的IOC。当然最复杂的要数avalon拉。

所以可以从pico入手看IOC,非常简洁(richard 在他的blog中连写了两篇文章夸 pico :) )
http://www.picocontainer.org/


to ajoo :

可以这么理解,目标pojo被修改字节码,已标志他实现了mixin的接口,当业务中造型pojo到mixin接口,并调用mixin的方法时,pojo会delegate这个调用到mixin的实现。这样就可以让pojo实现多重继承。

呵呵,说着说着就说到我不懂的东西了。没有用过ejb的东西,所以插不上口。

还是重复一下我的那个问题:

如果对updateData()和createData()都有pointcut和advice,那么,在create()调用update()的时候这个advice到底是否被执行?


void createData(){
...
updateData();
}
void updateData(){
...
}

我认为这很关键。

答案如果是肯定的,那么aop确实实现了OO所实现不了的语义。但是,也表明用aop来实现oo的pattern (如那个lock的bridge或者observer)是不合适的。aop和OO根本不相交,不能互相取代。

如果答案是否定的,那么aop和oo似乎就没什么本质区别,也许可以算作一个支持更直接更丰富的proxy实现方法。

to noxel
PICO确实不错,我感觉用它来编写自己的应用服务器等非常棒,我编写了很多Service类,到时通过xx.start()就可全部启动,这类似Apache的digest。

banq,
仔细看了一下这个bob的文章。

不错,他的看法我完全赞同。如果真需要设计一个可重用的observer pattern,我想我应该也会做得和他的差不多。(不需要一个单独的编译器,最多一个小的方法选择解释器,或者甚至直接用java reflection的语法)

只不过,我一直没有认识到这么做的重要性。每当需要写observer的时候,比较一下这样做的effort和多写几行pattern代码的代价,我总是会选择不去捣这个乱。

Bob的这个解决方法比我从那个aspectJ照猫画虎写的对应的java代码实现要更干净。我就一直看着那个aspect的设计比较土。

我这人比较执着于类型安全,对cast, reflection比较抵触,所以每当权衡是手工写委托代码还是用dynamic proxy的时候,总是类型安全的“良知”占了上风,孜孜不倦地去写委托代码。
我的理由是:委托代码虽然繁琐,但是,它几乎不包含任何逻辑,所以,节省它并不能带来太大的好处。
而手工委托的好处是灵活,你随时可以加入任何逻辑。当接口版本变化,编译器会强迫我必须对新增加的方法写委托代码,这样避免了盲目委托未预期的方法的问题。(当然,换个角度,这也是好处,你可以认为所有新方法都是直接委托,可是,我总觉得未来不可预见,还是见招拆招稳妥)
当有方法从接口中去掉时,编译器也会强迫我去掉那多余的委托代码。
而且,手工委托不需要cast,让我心理舒服好多。:)

请问AOP高手一个问题
AOP的纵向划分概念和C++的模板机制所期望目的是否一致?

谢谢

C++的模板好像自己的目标就很难定义吧?

类型安全方面,如stack<int>什么的,Generic Java会加入,但是和aop并不相交。

meta-programming,编译期计算方面,是c++独有,Java并无意于此。

类型计算,如type list,也是c++自己的玩具,和aop仍然没有关系。

parametric polymorphism方面,就是所谓的concept-model了,这和OO的programming against interface实际是相同的理念。

当然,模板确实有所谓的mixin,如:



template<class T>
class Subject: public T{
.......
}

这里,可以在父类未知的情况下,可以事先书写准备重用的代码。在这个observer的例子中,确实可以达到一些重用observer代码的目标。
我想,这是模板和aop目标最接近的地方吧。

比如说,下面的c++代码应该可以做类似的事情:



template<class T>
class Subject: public T{
void addObserver(...){...}
void removeObserver(...){...}
void subjectChange(){...}
Subject(const T& other):T(other){...}
}
class LineSubject: public Subject<Line>{
void setP1(Point p){
Line::setP1(p);
subjectChange();
}
void setP2(Point p){
Line::setP2(p);
subjectChange();
}
}
class PointSubject: public Subject<Point>{
void setX(int x){
Point::setX(x);
subjectChange();
}
void setY(int y){
Point::setY(y);
subjectChange();
}
}

呵呵,不用aspect, 不用dynamic proxy,几乎可以做到aspect所有的事情了。

一个问题是:Subject<T>的构造函数非常麻烦。Subject<T>的mixin是通过内部包含一个T类型的子对象完成的。而这个子对象如何构造呢?因为不知道T的具体类型,也就不知道T的所有构造函数。
于是,唯一能用的就是拷贝构造。

可是,这里,要构造一个LineSubject,就要先构造一个Line对象,然后,在把它拷贝到LineSubject里面去。这个效率就是个问题。
而且,对某些不能拷贝的类又怎么办呢?对singleton对象怎么办呢?

可惜,这个mixin方法即使在Generic Java中也不支持,erasure model不允许直接继承一个T。
我正在考虑一个delegate model,也许可以用来在Java中做类似的mixin。等我想得再清楚点再说。

我的理由是:委托代码虽然繁琐,但是,它几乎不包含任何逻辑,所以,节省它并不能带来太大的好处。
而手工委托的好处是灵活,你随时可以加入任何逻辑。当接口版本变化,编译器会强迫我必须对新增加的方法写委托代码,这样避免了盲目委托未预期的方法的问题。(当然,换个角度,这也是好处,你可以认为所有新方法都是直接委托,可是,我总觉得未来不可预见,还是见招拆招稳妥)
当有方法从接口中去掉时,编译器也会强迫我去掉那多余的委托代码。
而且,手工委托不需要cast,让我心理舒服好多。:)

所以我认为 Borland 捡到了一块宝地,他看到了我们现在才能看清楚的市场。使用语言特性(如 OO, AOP) 不能很好有效的解决编程中的各种问题。而使用编程工具自动生成与维护代码才能更用效更好的解决问题。

呵呵,banq,我昨天仔细想了好久,关于这个Bob的dynamic proxy方法,我唯一不喜欢的就是它要求用户使用stupid cast,也就是说,从Line到Subject之间的cast。

这很不安全,万一用户不小心从一个没有经过proxy的原始Line对象cast到Subject,就会出问题。

而这里,问题的关键,还是Java语言不支持静态的proxy(比如类似上面一个帖子中的C++的mixin)。
假如,Java语言能够支持一个delegate model,比如:

一个connection pool的示例代码(一般都用dynamic proxy实现):


class PooledConnection implements Connection{
private final Connection conn;
private final Pool pool;
private bool closed = false;
public PooledConnection(Connection conn, Pool pool){
this.pool = pool;
this.conn = conn;
}
public delegate conn: Connection{
precondition();
delegate;
postcondition();
}
public void close(){
if(!closed){
pool.release(conn);
closed = true;
}
}
private void precondition(){
if(closed){
throw new ConnectionClosedException();
}
}
private void postcondition(){...}
}

说明:

这里,delegate是一个keyword,它表示编译器自动加入委托代码。
一。
conn:Connection表示对conn对象做委托,而且只委托Connection接口里面的方法。(这可以用来做filtering)

二。
委托所带的是一个block。这个block是optional的。如果不带一个block,就是最简单的直接委托。
它内部可以带任意合法的block。特殊之处,是:
1。所有分支都必须或者throw 一个RuntimeException,或者return delegate()。
2。delegate()是一个特殊的函数,它代表调用被委托的函数,所有参数都被传递。
3。return 只能是return delegate()
4。delegate()可以不用return而直接调用。
5。delegate()的返回值未知。

三。
在类中直接定义的方法,可以override delegate的方法。

四。
如果一个类中定义了两个以上的delegate,那么任何两个delegate中的方法不能互相冲突。(即可以被认为一个方法的签名override了另一个)


从上面的示例代码可以看出,before, after等advice都可以加。
也可以用直接定义的close()来override委托函数。


下面,我在写一下对应observer pattern的代码


interface Observer{
void fireEvent(Event event);
}
interface Subject{
void addObserver(Observer ob);
void removeObserver(Observer ob);
void subjectChange(Event event);
}
class SubjectImpl implements Subject{
public void addObserver(Observer ob){...}
public void removeObserver(Observer ob){...}
public void subjectChange(Event event){
for all ob in observers
ob.fireEvent(event);
}
}
class LineSubject implements Subject, Line{
private final Subject sub;
private final Line ln;
public delegate sub:Subject;
public delegate Line;
public void setP1(Point p){
ln.setP1(p);
sub.subjectChange(new LineChange(ln));
}
public void setP2(Point p){
ln.setP2(p);
sub.subjectChange(new LineChange(ln));
}
public LineSubject(Subject sub, Line ln){
this.sub = sub;
this.ln = ln;
}
}

这样,也可以达到重用observer代码的作用,而且,引入的额外东西比aspect要少,类型上和代码的简单程度也比dynamic proxy好。

各位觉得如何?

上面贴的代码有点小问题,改正了一下。iceant,你觉得如果语言特性加上这个delegate,是否就用不着aop了?


connection pool:


class PooledConnection implements Connection{
private final Connection conn;
private final Pool pool;
private bool closed = false;
public PooledConnection(Connection conn, Pool pool){
this.pool = pool;
this.conn = conn;
}
public delegate conn: Connection{
precondition();
try{
return delegate();
}
finally{
postcondition();
}
}
public void close(){
if(!closed){
pool.release(conn);
closed = true;
}
}
private void precondition(){
if(closed){
throw new ConnectionClosedException();
}
}
private void postcondition(){...}
}

observer pattern:


interface Observer{
void fireEvent(Event event);
}
interface Subject{
void addObserver(Observer ob);
void removeObserver(Observer ob);
void subjectChange(Event event);
}
class SubjectImpl implements Subject{
public void addObserver(Observer ob){...}
public void removeObserver(Observer ob){...}
public void subjectChange(Event event){
for all ob in observers
ob.fireEvent(event);
}
}
class LineSubject implements Subject, Line{
private final Subject sub;
private final Line ln;
public delegate sub:Subject;
public delegate ln:Line;
public void setP1(Point p){
ln.setP1(p);
sub.subjectChange(new LineChange(ln));
}
public void setP2(Point p){
ln.setP2(p);
sub.subjectChange(new LineChange(ln));
}
public LineSubject(Subject sub, Line ln){
this.sub = sub;
this.ln = ln;
}
}

>这很不安全,万一用户不小心从一个没有经过proxy的原始Line对象cast到Subject,就会出问题。

一般不会发生这种情况,因为Cast的东西就是你输入的,这类似COllection,你将类放入,取出需要Cast一样。

从JDK1.3以后,Java对Cast支持性能有很多改善,特别是JDK1.4,因此基本可以不必象以前版本那样投鼠忌器地使用Cast,Cast是个好的有效的方式,我这样认为。

to ajoo
你这段代码完全可以实现动态代理的功能,动态代理的诞生主要理由不是为了为用户提供一种更多选择,而是为了实现MetaLevel级别编程,类似人类思维最后都是从具体物理学、化学、社会学抽象到哲学这个更高级别讨论一样。

Metalevel编程可以协助诞生更多框架产品,最近程序员杂志那个学庸又大放厥词,Java没钻研深入,改尝.NET,自以为在.NET中发现了MetaData的很完美解决方案,还可笑地说:“Java爱好者别担心,马上你们会有的“,其实这是他可笑的孤陋寡闻,Java MetaData开源我已经看到好几个,只是暂时记不得网址,前段时间我还想使用MetaData通过肥客户端直接访问数据库,将数据库数据挖掘研究直接提供给终端用户。

我不是想攻击谁,我实在看不惯任何不了解的自大言论,我对.NET不了解,所以我从来没有提及或和.NET比较过,台湾人还真以为大陆都是非MetaLevel水平的。

话说多了,绕开去了,动态代理是Java语言本身提供一个机制,也就是Java语言开始自己抽象自己、自己描述自己的MetaLevel编程机制,这是个很重要的新的征途开始。

在我的书籍《Java实用系统开发指南》中专门对动态代理进行了解剖和使用。

呵呵。这就是一个美学范畴了。我是讨厌cast的。
如果用cast,往往用户需要这样:


Subject sub = (Subject)register(line);
sub.addObserver(...);
Line sline = (Line)sub;
use_line(sline);//这里如果万一用了line,可能就会出问题呀!
....
Subject sub2 = (Subject)line;
//不好!应该是sline的!

java 1.5应该会加入generics了吧?到时候,我们就不必从Collection里面取出来然后cast了,我们可以直接

Collection<Car>

以前Java是为了简单,才不加入generics的,但不是说cast的危险不存在。还是能避免就避免的好。虽然有ClassCastException,但是效率低不说,运行时找到问题还是不如编译时找到好啊。

至于我这个delegate的想法,目的不是为了取代dynamic proxy,它也不能在一些要求比较细腻的情况下(比如说,filter所有叫做hello*的函数)代替dynamic proxy的功能。
它的目的主要是为了提供一个type-safe的并且写起来比较handy,更易读易懂的proxy的选择。

另外,如果比较delegate方案和aspectJ,你觉得aspectJ方案有什么独特的优势是delegate所不能提供的吗?纯粹技术讨论,可不是狂妄到想说我随便相出来的东西就肯定比人家花了那么多精力作出来的aspectJ强。^_^

怎么字不小心变小了?读起来太费事,重新贴一遍吧。

java 1.5应该会加入generics了吧?到时候,我们就不必从Collection里面取出来然后cast了,我们可以直接


Collection<Car>

以前Java是为了简单,才不加入generics的,但不是说cast的危险不存在。还是能避免就避免的好。虽然有ClassCastException,但是效率低不说,主要还是运行时找到问题不如编译时找到好啊。静态类型安全最好还是不要轻易牺牲。尤其是强迫客户代码cast,更不舒服。

至于我这个delegate的想法,目的不是为了取代dynamic proxy,它也不能在一些要求比较细腻的情况下(比如说,filter所有叫做hello*的函数)代替dynamic proxy的功能。
它的目的主要是为了提供一个type-safe的并且写起来比较handy,更易读易懂的proxy的选择。

另外,如果比较delegate方案和aspectJ,你觉得aspectJ方案有什么独特的优势是delegate所不能提供的吗?纯粹技术讨论,可不是狂妄到想说我随便瞎想出来的东西就肯定比人家深思熟虑作出来的aspectJ强。^_^

AOP 不是一个很好的话题。不是说AOP不好,可这个话题太大,就像Jdao开了一个OOP的讨论一样。

AOP诞生快10年了,但是,对于我们还是很新的,当大家刚刚对对象有了感觉,AOP又把对象给打散了。AOP概念很清楚,就是横切(当然还包括其他的元素),就像2000年sina,sohu在疯狂的作门户的时候,跳出了塞迪等网站说要做垂直服务一样。从而打破了程序代码由上到下执行的顺序。

10年前出了OOP,我个人认为未来的10年就是OOP得天下了,这将是我们这些程序员很高的一个学习曲线。

AOP真得不好说,概念就是这个样子,看如何实现了。我对AOP的入口是在Spring, 了解不深,总是半斤八两,说来惭愧。
不过,需要给在本帖中提到spring的guys说一下,spring不是一个framework(I consider),是一个容器,就像Java vm 在OS上建立了一个plateform 一样,spring在J2EE 上面建立了一个容器,让你更好,更方便的管理Bean,component,class谁知道叫什么呢,反正就是那些个Object了。

呵呵。我迷惑就迷惑在AOP的概念上啊。说是横切,怎么个横切?
就banq给的几个例子,虽然说可以解释成“横切”,可是,仍然和OO并不矛盾。

我理解的OO就是简简单单的对接口编程而已。而接口的设计,根据不同的考虑角度,会有所不同,变化之妙,存乎一心啊。

这些observer, container,如果根据分离变化的宗旨,设计出来的接口就是和AOP追求的目标一致的。

那么,莫非AOP就是对这样一种设计思路的总结?是一种模式?

但是为什么大家总是把AOP当作一种和OO完全不同的崭新思想方法,而不是一类pattern呢?