Author: Anders小明

产品化和客户化两个词语是一个对孪生兄弟,一个没有强大客户化能力的软件是不能称为产品化的软件.产品化也就意味着软件公司的开发至少分为两个不同性质的角色:一个负责产品化,一个负责客户化.除去传统的参数化, 继承以及plugin技术外,aspectJ为我们提供另一种能力.

如前所述, 公司有两个不同角色的团队在开发和维护—研发组和项目组,更进一步,本文所说适应如下的开发团队结构:
一个研发组---多个项目组, 每个项目组需要定制化的东西各自不尽相同. 为了保证几个团队的工作的相对独立性,公司希望项目组在做客户化过程中不改研发团队所开发的代码,应用了已知的方法:参数化, 继承以及plugin技术外.

然而这些技术并没有覆盖到所有的问题, 问题描述如下
使用AspectJ应用的方法

经过分析发现需要客户化的地方,是需要在Root类里加一个propertyA, 这个时候基于已有的能力,我们可以做的选择是要么项目组A在修改Root类,要么修改每个叶子类(LeafA....), 显然修改root类是一个不错的选择. 然而槽糕的是,项目组B需要是添加另一个properyB,于是项目组B也这么做了. 对于项目组A和B来说这样做是没有太多问题的.
但对于研发组来说问题却是很严重的, 由于研发组需要从项目回收代码,以便吸取优点改进软件,研发组不得不小心的维护各个版本,并处理项目组所做的修改.而同时项目组获取了修改研发组代码的权力,处于时间的压力,会产生不符合系统结构约束的代码.
很明显,这样的工作方式不利我们的工作,我们需要一个新的思路.

在正式提出新方法前,我想先介绍一下微软的DSL Tools以及C# 2.0,各位客官,还请耐心的看一下。
DSL Tools是微软开发的Domain Specification Language,目的是用更接近于业务的语言模型来描述业务问题,并生成运行代码。工具允许其用户定义各自的Domain Language,目标是软件工厂。DSL Tools面临的一个问题(也是公司目前面临),定义好的DSL以及生成代码,不可避免的出现不同客户存在细微的差异性,DSL Tools必须很好的解决它,事实上DSL Tools的确做到了——它基于是C#2.0 Partial Class技术。(有关于DSL Tools的更多信息可以参见MSDN)。
简单说的Partial Class的其实就是一个类的结构信息可以被存储在多个文件中,以下是个例子:

file1.cs(微软的一个文件可以定义多个类,所有其文件名不需要同类名):
public partial class CAgent {
private String name;
Property String Name{
get{
return name;
}
set{
this.name = name;
}
}
public void doSomethingA(){
....
}
}

file2.cs
public partial class CAgent {
private String code;
Property String Code{
get{
return code;
}
set{
this.code= code;
}
}
public void doSomethingB(){
....
}
}
虽然CAgent类被分解为两个文件,不过对于调用者类说,CAgent具体name以及code两个property,以及doSomethingA和doSomethingB两个方法。
现在你可以想象DSL Tools是如何解决客户化这个问题的了!
DSL Tools生成的所有class都是partial class,当对于CAgent(或者其它类)有需要客户化时,需要做的只是添加一个新的文件,用同样的类名加上一个partial的关键字,
public partial class CAgent 就可以添加新的属性和方法(如同我展示的那样,想象一下file1.cs是研发维护,而file2.cs是项目维护的)。也就说,DSL的研发团队和客户化团队的工作时相对独立的。

那么你一定会说,这个微软的C#,不幸的是公司用的是Java,java的语言规范不支持这样的能力。
是的,你说的很对,Java语言本身是不支持,不过我们有这样的手段——那就是AspectJ。
实际上AspectJ面世很久了,我接触它至少有一年半了,不过支持一直没有想到这样的用法,直到我研究了DSL Tools(我相信很多道理是相通的,我们目前面临的问题硅谷的那帮人也一样面对过)
下面是一个简单的例子:
OnType.java:
public class OnType {
public void doAction(){
System.out.println("OnType.doAction");
}
}

OnTypeAspect.aj
public aspect OnTypeAspect {
public String OnType.name = "OnTypeAspect";

public void OnType.doActionAspect(){
System.out.println("OnType.doActionAspect and name is "+ name);
}
}

Main2.aj
public class Main2 {
public static void main(String[] args){
OnType onType = new OnType();
onType.doActionAspect();
}
}

如你所见,程序是可以完整的运行。你的控制台打出了:OnType.doActionAspect and name is OnTypeAspect
不仅如此,AspectJ可以为已有的类添加新的接口,就像C#的partial class做的那样。

我以为aspectj是实现我们的目标的一个捷径,并且它是经过实践的,我不相信aspectj和微软的那帮人会闲着没事来支持这样的技术。BTW,我听说weblogic的jrockit准备在虚拟机一级上支持aspectj, 那么或许剩下的工作就是如何管理使用AspectJ了.