motv – 电视节目表

  • 一个关于看电视的想法.有点类似豆瓣的意思.
  • 通过电视节目列表用户可以很容易的搜索到自己感兴趣的节目,并可以收藏,添加到提醒. 比如短信和邮件的提醒.
  • 所有的节目通过标签进行分类.
  • 用户可以对节目添加自己的评论
  • 通过用户对所有节目的标签和收藏,将用户细分.从而提供进一步的定制服务.比如类似豆瓣的”你可能会喜欢看xxx”
  • 这个应用也是我很想要的,因为现在电视频道实在太多,而传统的电视指南的查找功能有限.不得不承认还是有很多很好的电视节目.这个应用的目的就是过滤掉那些对用户来说没用的噪音,帮助他们找到想看到.
  • 而通过对用户的细分,用户之间也可以通过共同的喜好找到志同道合的朋友.也和豆瓣一样.为什么豆瓣不弄一个呢?

如何实现改变JTable中的曾选中过的cell的背景

 

2006/5/14

扩展一个JTable,增加一个List记录每次点击选择的cell,将其index记录.然后用一个Renderer,如果cell被选择过,则修改背景颜色为红色.使用时候先实例化一个MyTable,在setCellRenderer.

public class MyTable extends JTable {

private ArrayList selected;

public MyTable() {
super();
selected = new ArrayList();

}
//将选中的cell列,行数记录
public void addSelected(Point p){
if(selected.contains(p)){
selected.remove(p);
}else{
selected.add(p);
}
}

//某个cell是否被记录过

public boolean hasSelected(int row, int column) {
return selected.contains(new Point(row,column));
}

}
实现一个renderer,当cell的index在记录历史中,则修改其背景

public class MyRenderer extends DefaultTableCellRenderer{
public MyRenderer(){
super();
setHorizontalAlignment(SwingConstants.CENTER);
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
MyTable mt = (MyTable)table;
if(isSelected){
mt.addSelected(new Point(row,column));
}
if(mt.hasSelected(row,column)){
this.setBackground(Color.RED);
}else{
this.setBackground(Color.WHITE);
}
return this;
}
}

最近在用的软件

Gmail Mobile
如果要在手机上使用Gmail,要用这个.另外一个Mail For Exchange,如果要接收来自exchange的邮件就要用这个.

Prism
Mozilla的新玩意(新名字老玩意),可以把web应用做成桌面shortcut(“桌面化”–新词).如果你经常用诸如gmail,googledoc,googlereader,googleearth,flickr,youtube或其他一些web应用….可以试试

Y’z Dock
可以在xp/vista上带给你mac风格的dock.这里有很多docklet下载

Faststone Capture
Shareware,是我见过最贴心的截图工具,但有portable version…

WordPress
就是这个blog

google输入法
其实一直都是紫光的粉丝,只是一次次受打击(先是词库莫名其妙变小,一些很寻常的词居然也会找不到,后来又是莫名其妙的认为我是大舌头,- -比如我打dashetou,她会给我大色头).本来想用搜狗输入法,虽然名字很难听,可是在往没有中文支持的xp上安装时候变成乱码.最终选了这个.反正我也不在乎google和sohu的字库问题.而且用到现在觉得还不错.

写商业计划书之前要做的10件事

翻译-写商业计划书之前要做的10件事
原文

撰写计划书之前最好研究一下计划书应该包含哪些部分.

1.研究所有相关章节
开始写之前,确定你已经理解必要的章节,不同章节的目的和计划书的目标. Business Plan Pro(r)
2005之类的软件会帮助你确保不会漏掉任何章节.但如果你选择自己写,可以参考这两个网站:www.bplans.co.uk和www.businessplanhelp.co.uk,他们会帮助你全面了解每个必要的组成部分,写出令人信服的商业计划.

2.决定法律结构
尽管大多数的企业关注于”创意”或者”想法” — 这是可以理解的,但是日常执行和后勤也是不可忽视的.例如,在做贸易的时候,你要决定是单一供货商,合伙制还是有限公司.决定之前,列出当地的会计师和业务关系或者通过网站(www.startups.co.uk)研究不同选择的特点.类似的,诸如了解你的增值税义务(原文:VAT obligation),注册商标或公司名,以及起草员工合同都需要被考虑到.

3.掌握数据
无论你是否喜欢统计数据,深入地了解会影响到你业务的数据是你成功至关重要的因素,尤其是在计划阶段.开始阶段了解以下这些非常重要:
.你的启动成本
.你的盈亏平衡点
.你的资金需求
.你的之后几个月的现金流预测
免费的计算器可以帮助你计算这些数据.强烈建议你通过一个基本会计打包(原文:basic account package)建立你的业务.QuickBooks(r)
(www.intuit.co.uk) 或 Sage(r) (www.sage.co.uk)会提供这样的服务.

4.获取行业分析数据
尽管你拥有独一无二的地方,但是仍然有很多与你相似的公司存在,作一些市场调研会帮助你更好的了解你的目标市场.
所有的公司被英国政府使用标准工业划分系统(SIC)分为不同的类别;先找到你所在的类别并找到你的SIC编码.这会帮你搜索到你竞争对手和其他业界参与者的有关资料.然后通过类似Cobweb
(www.cobwebinfo.com)的数据源寻找更多的数据资料.Cobweb提供大量的商业档案资料.这会让你获得外部的视角来分析业界其他类似公司.

5.研究市场
当准备投放广告时,不如先使用www.overture.com的关键字助手看看哪些与你的业务或服务有关的关键字被搜索的最多.这会帮助你有效的投放广告或确定一个URL或者使用搜索引擎优化来优化你的网站.你也可以通过输入这些关键字到搜索引擎来找到你的竞争对手.

6.慎重评估需求水平
与估计成本不同,最难预测的事情是你的产品或提供的服务的需求水平.通常的规则是保守地估计可能的需求和使用相似取代方法.
即便是一个新的独一无二的创意也应该用相似取代来估计,而不是凭空编造数据或说自己没有可以比较的数据.一个经典例子,最近伦敦旅游发展项目的昙花一现.一个最主要的问题就是游客的数量远远低于预先估计的数量,因此入不敷出.如果负责人事先研究过英国最主要的吸引游客的地方,他们就会找到潜在游客的上限数量.由于估计的游客数量高过这个上限,这个疯狂的优化假设造成最终的失败 — 成本和收益远不成比例.

7.进入市场策略
由于竞争的激烈,企业家要慎重选择如何进入市场或如果打动客户的芳心.大多数新的公司会考虑为他们的新品牌采用多渠道进入的策略,但是这样做不仅仅成本巨大,而且比单一渠道昂贵许多.互联网营销是一个很吸引人的策略,因为营销成本容易跟踪.此外,找到当前相似市场的供应商所处的位置也可以告诉我们哪些市场活动是最有效的.当然,这些是建立在正确的数据上的.

8.雇用合适的人
除了财务方面的估计,执行力强并可以信赖的人是潜在投资者要研究的.无论企业家和创建人的技能水平如何,他常常是需要协助的.尽管很多非核心的活动是可以外包的,某些部门,例如销售,还是需要随时关注的.你应该列出所有的必要技能,把他们放到模型里定价,发现缺口并合适的候选人.

9.定义并明确客户获得的好处
许多企业家无法清楚的说出他们的所做的事能够带来的好处.因此,”电梯行销”这个词被引入到现代词汇来解决这个问题.–所谓的电梯行销是,你的创意,以及支持他的商业模型,公司方案,市场策略和竞争手段需要你在一段电梯升降的过程中表达出来.
这个简单的方法目的是让企业家用心地思考在描述他的产品或服务时如何使用语言的艺术.同时也是提醒他们要以客户为中心并确保他们集中精力描述这些”好处”.

10.找一个导师
许多的创业者会妄想他们的创意会被别人偷走,并在开始前表现的很不理性.通常,创意都是严密的保护并且只在知己讨论.但是这些”知己”(一般是家人或朋友) 通常很难提出足够具有挑战性的问题因为一来他们不愿意冒犯你,二来他们缺少相关的经验或足够的判断力去严格地分析这个新的风险.正因如此,有重大缺陷的创意可以在还没有“关键时候掉链子”的时候被及时纠正,从而可以正常地发展。强烈建议创业者在早期找一个独立的导师帮你审视你的创意。这些人可以帮你在向投资人或者银行展示之前“敲打”你的创意。最后,形成鲜明对比的是,一些创业者觉得投入越多越好,他们参加每一个商业计划竞赛来获得独立的反馈而不是获奖。

精通技术一定就是一个好的程序员???

19:44 2006-10-10 精通技术一定就是一个好的程序员. 这句话是完全错误.”好的” – 这种东西本身就是一个很模糊的概念.就算是真的大家对”好的”这个标准一样了,对”程序员”的定义又不一样.对”精通”的定义也未必一样.”程序员”的定义取决于,通常情况下,”程序员”应该具备的素质,而这些”素质”本身又存在的定义理解上的差别.因为bull shit终归还是不同的人来看的.而”精通”的概念就更不要说了,我是从来没有弄清楚过,很多时候这样的词是需要context的,可是这里的context也是含糊的–>

所以呢,唉,..

不要觉得我在玩弄概念,其实很多情况下我们是被概念玩弄,想想经常可以看到论坛或者日志的回复都是一些不知所云的家伙,要么是根本没有用大脑,要么就是没有搞清楚出发点在哪里.

这是tm扯到哪里去了.又说胡话了.
一般说”精通技术一定就是一个好的程序员.”这句话的时候,context还是确定的,所以还没有到无法讨论的地步.不过确实是”完全错误”的.首先我不会去贬低钻研技术的同志们,毕竟人个有志.所以如果有逻辑不是很清晰的同志们不要认为我在说”精通技术就一定不是一个好的程序员”或者”好的程序员不需要精通技术”.
程序员是搞技术的,当然要精通技术咯.可是要是埋头钻研技术期望做一个好程序员,那就错了.错的不靠谱.软件的主要参与者是人,好的程序员显然不是单单技术.做什么事情终归还是和其他人一起做,协作.技术高了可以抵掉一部分协作,比如如果你的效率是其他人的10倍,你当然没有必要去沟通去浪费时间去plan,document,kt…, 虽然可以这样的做,但从时间角度也是存在协作的,你的东西存在以后被别人看到,维护的可能.如果你觉得”这个我不管”,”不是我的事情”,那你不只是做不好程序员,而且是个不负责任的人(这样的人最危险),做什么事情都恐怕都不是”好的”. –这样的人”好的”定义和我不一样, 请滚.
所以对技术不要盲目崇拜,我们遇到的问题通常并不是仅仅技术一维.
这些话送给我自己,如果有人觉得有道理,那满好,如果觉得是狗p,抱歉浪费了您的时间.

这是很久之前写在msnspace里的,重新放到这里给自己…

e61i新玩法 – Mobile Web Server

在e61i上搭建自己的mobile网站,然后可以用PC在任何地方连接你的e61i.可以方便的共享,只是似乎速度比较慢.

1.下载 MobileWebServer 下载
2.如果已经有装S60的Python,要先删除.然后再安装 MobileWebServer
3.需要注册一个用户,然后email验证.同时提供一个二级域名,如: zhangv.mymobilesite.net
4.用e61i连接网络,启动MobileWebServer,用之前注册的用户登录

这样就可以通过Internet访问你的手机的共享资源了.截图看这里.当然需要先登录. 你可以通过设置启动guest.如果你总是时刻都在线而又有很多有趣的东西共享给其他人.这是个不错的选择.或者你喜欢用一个web的界面来操作你的e61i,比如你把手机丢在家里而手机的webserver是启动的,那你照样可以在办公室里通过你的e61i发送短信,共享文件,查看通讯录…更牛x的是可以创建一个手机的blog,当朋友访问你的手机site的时候可以随时看到你的最新动态.

未知的问题:
1.安全性还不知道,可能现在使用无线的用户不多吧
2.在手机上运行这个webserver是不是会占用太多的资源

最近在读的书

<<少即是多>> Seth Godin

虽然这本书很”畅销书”,因为里面的152个妙想大多数都颇有启发性,至少对我. 另外很重要的一点就是他们都很短小,很适合现在大多数”沉迷”快餐文化的可怜人(包括我).

<<中国人的精神>> 辜鸿铭

认识你自己

<<丑陋的中国人>> 柏杨

第二遍,时刻提醒自己

<<5分钟和陌生人成为朋友>>

发现自己在社交方面有点问题,有点像宅男方向发展

Playin’ with E61i

  • 邮件(Email)

Mail For Exchange ->用于Exchange邮件
GmailMobile -> 收Gmail的客户端
BlackBerry Connect ->没用过还
可以通过配置imap来收gmail邮件。似乎更好

  • 无线(WIFI,WLAN)

Fring ->可以通过skype,msn,googletalk,ICQ,twitter或sip服务进行语音通话
Gizmo ->费用不详

  • 软件(Software)

ScreenSnap ->屏幕截取
Google Maps Mobile ->google地图手机版
Opera Mini ->Opera网络浏览器,还是觉得e61i自己的浏览器好用一点.有备无患.用Gmail有问题,而且速度慢
FaceWarp ->变脸,比较好玩
DivxPlayer ->视频播放器
CorePlayer ->我觉得比divx播放器好一点,不过对我来说都差不多,因为并不常用
掌上书院 ->看书的,可以收藏,添加书签,在线下载…支持图片
QReader ->更好地看书软件,速度快使用方便,界面清爽,只是不支持图片
Handy Clock ->强大的时间管理工具,包括世界时钟,世界地图,我主要用闹钟
Handy Profile ->情景模式管理,定时,自定义切换规则
Handy Taskman ->任务管理
AgileMessenger ->all in one的im工具,支持yahoo,msn,googletalk
F-Secure ->防火墙,有备无患
MobyExplorer -> 文件管理器,同时支持ftp
Resco Photo Viewer ->图片管理
Putty -> e61i连接ssh
iSkoot ->e61i上的skype客户端,通过一个本地的网关来连接skype,应该是只支付本地电话费.香港可以,目前不确定国内是否支持.到mosh下载
smart2go ->地图下载,不需要网络连接(不同于googlemap).下载了上海和北京的地图却看不到详细的街道名.
MGtalk ->开源的jabber/googletalk客户端,虽然界面不是很美观,但是因为不像fring那样的proxy client,所以要安全一些.同时还有gmail提醒功能.
Talkonaut ->很棒的im工具,支持gtalk和msn。但是不支持中文输入。
ZTA4 ->最好的输入法
MsnMessenger ->官方的移动客户端,但在香港使用有问题,国内使用GPRS正常.
MoFire -> 我自己写的在手机上发布blog的工具

  • 游戏(Game)

S-Tris2 ->俄罗斯方块
Snake ->Nokia的经典游戏,这个是3250的下载页面,可用
iNES ->FC(红白机)模拟器
vNES ->经典的symbian上fc模拟器,建议大家去买,国产的共享软件,只有25rmb。ines好像是30美刀
古墓丽影 ->还用说吗
SkyForceReloaded -> 傲气雄鹰,如果用nokia不知道这个游戏就有点土了
MicroPool -> 桌球
Chinese Chess -> 象棋,电脑有点笨,操作起来稍显麻烦。
上面的三个到s60.s80.cn下载

  • 在线(online)

GoogleReader -> Google在线rss阅读器
GoogleCalendar -> Google日历
Flickr -> 照片管理
Youtube -> 16亿,e61i内置的浏览器因为没有flash内建支持所以没有办法看

  • 关注(keep watching)

Deepfish -> 微软的mobile浏览器

  • 资源(Resources)

SymbianV3
Series60v3.com
My(and your) E61
Nokia E61 Blog
Wendong’s Smart Phone Weblog
Eseries
MOSH
推荐!
S60下载推荐

最后更新2008-2-1

AOP与OOP

(最初发布在JavaResearch.org,现在整理好放到自己的地方.)

作者:Narayanan A.R. June 15, 2005
翻译:ZhangV 2005-06-28
原文出自:DevX.com
原文链接:http://www.devx.com/Java/Article/28422/0/page/1

首先你要明确的一点,AOP和OOP是两种不同的认识事物的角度,并不是说有了AOP就不要用OOP.AOP所关注的是传统OOP不能优雅解决的问 题.(程序员通常都是完美主义者,当解决某个问题不优雅的时候,那就意味着不完美.)下面将就一个简单的例子来说明他们到底如何的不同.

作为一个使用OOP多年的人来说,当我听说AOP可以解决一些OOP一直都不能优雅地解决的问题时,我觉得应该去探个究竟了.对两种技术的比较最能给我们实际应用提供见解.这里我设计了一个例子:一个OOP应用,其中某些方面适合使用AOP.

本文展示了一个简单的例子.一开始介绍了问题域,然后分别给出传统OOP的解决方法与结合了AOP解决方法.后者使用了 JDK5.0,JUnit,和 AspectWerkz.最后我会说明如何编写代码.读完本文后,我希望你能知道AOP到底是什么,用来解决什么样的问题.

问题域描述
一个软件公司雇佣一个程序员,指定给他一个业务部门并要求他随时向经理报告.当团队成员完成他们的目标时,经理会给他们相应的奖金.公司所需要的方案必须能够增加一个新的雇员并给当前的员工增加奖金.为了方便,我们用CSV文件存储数据.


图1 解决方案模型

类Manager(经理)继承自类Employee,包含一个额外的属性,Managing Project.一个部门可能包含很多员工.多个部门构成了公司.暂不考虑公司这样的一个类,因为它在问题域之外.

解决方案设计
以下流程图描述了解决方案设计.


图2 对象之间的交互(增加一个新的员工,指派给他一个部门和经理)

出于简单的考虑,本文只关注必需的细节.你也可以深入代码得到你想要的其他信息.
下载
EmployeeServiceTestCase, 一个JUnit测试用例,模拟一个最终用户,创建新员工记录,指派部门和经理.它获取所有可用的部门和经理数据并显示在图形界面上.为了实例化域对象 BusinessUnit和Manager,获得的记录将传递给工厂类.之后,通过给EmployeeService传递一个引用来创建一个 Employee对象.这个服务类使用EmployeeFactory创建对象,并把这个对象传给EmployeeRepository 来进行持久化操作.

应用程序中需要面向哪些”Aspect”
到目前为止,对模型和设计的讨论还限于一个较抽象的层面.现在,我转向这个应用的其他方面 – 这对理解AOP的价值至关重要.

操作所需的资源

<pre lang=”java”>

public static Set findAllBusinessUnits() throws RepositoryException {
Set businessUnits = new HashSet();
try {
FileReader businessUnitFile = null;
BufferedReader bufferedBusinessUnitFile = null;
try {
businessUnitFile = new FileReader(FILE_NAME);
bufferedBusinessUnitFile = new BufferedReader(businessUnitFile);
String businessUnitRecord;
while((businessUnitRecord = bufferedBusinessUnitFile.readLine()) != null) {
BusinessUnit businessUnit = BusinessUnitFactory.createBusinessUnit(businessUnitRecord);
businessUnits.add(businessUnit);
}
} finally {
if(bufferedBusinessUnitFile != null) {
bufferedBusinessUnitFile.close();
}
if(businessUnitFile != null) {
businessUnitFile.close();
}
}
} catch(IOException ioe) {
String message = “IOError. Unable to find Business Unit records”;
logger.log(SEVERE, message, ioe);
throw new RepositoryException(message, ioe);
}

logger.log(INFO, “Manager Records returned:” + businessUnits.size());
return businessUnits;
}
</pre>

上面的代码通过FileReader和BufferedReader来读取CSV文件中的业务数据.
应用程序重复地从资源文件中取得数据然后在操作完成后释放. 我们会发现:去掉程序的这两个”Aspect”将提高代码的可读性并达到一个更好的设计,因为去掉这些”多余”的东西,剩下的代码才是这个方法真正的精 髓.这个方法的作用是读取业务单位数据.所以不应该也不需要去知道”如何获取和释放资源以及这个过程中出现的异常”这个”切面”.同样地,使用AOP处理 异常也变得不同.(后面将详细介绍)

持久层
传统的OOP使用持久化类(repository classes)来持久应用程序的持久层.即:

<coolcode lang=”java” linenum=”off”>
public class EmployeeRepository {

public static void createEmployee(Employee employee) throws RepositoryException {
//使用print writer把数据放入csv文件
}

public static String findEmployeeRecordById(String id) throws RepositoryException {
//使用file reader来获得指定id的员工数据
}

public static Employee findEmployeeById(String id) throws RepositoryException {
//使用该方法获取员工数据,Employee对象由工厂类创建
}

public static void updateEmployee(Employee employee) {
//更新员工数据
}
}
</coolcode>

类EmployeeService 使用一个EmployeeRepository给应用中相关雇员提供服务,在一个企业应用中,从域模型 (domain model)中去掉持久层代码是一种设计上的改进.模型设计者和程序员就可以关注各自的业务逻辑和持久层处理.后面你将会看到如何通过 AOP来达到这样的效果.

日志
删除用于调试的日志代码将会极大地改进代码的可读性.考虑下面的代码片断:

1.
2. public Employee createEmployee(String name,
3. String contactNumber,
4. BusinessUnit businessUnit,
5. Manager manager)
6. throws EmployeeServiceException {
7. String id = createNewEmployeeId();
8. Employee employee =
9. EmployeeFactory.createEmployee(id, name, contactNumber, businessUnit, manager);
10. try {
11. EmployeeRepository.createEmployee(employee);
12. } catch(RepositoryException re) {
13. String message = “Created employee successfully:” + employee;
14. logger.log(SEVERE, message);
15. throw new EmployeeServiceException(message, re);
16. }
17. logger.log(INFO, “Created employee successfully:” + employee);
18. return employee;
19. }

上面的代码里包含了一个致命错误和一个成功信息.输出日志这一”Aspect”同样可以移到业务模型外独立实现.

异常处理
异常处理的例子我这里不再赘述,但这节已经通过上面的代码讨论了潜在的问题.当你调用EmployeeRepository 对象的 createEmployee 方法时,你可能会得到一个RepositoryException异常.传统的解决方法是,在这个类中处理.另一种方法是,当 RepositoryException 异常被抛出时createEmployee 方法返回null,catch块中的其他逻辑可以在类外处理这一错误.
错误处理在不同的情况中也会不同.但是,通过AOP可以区分开每种情况.

图3

图3中描述了AOP方法的设计以及在一个更抽象的层次上类间的交互.你可以通过对比图1和图3来更好地理解AOP.
程序的目的是通过BusinessUnit对象读取CSV文件中的记录然后填入类BusinessUnitService 中的map.使用AOP来填充这个map有点类似后门(backdoor)方法 — 控制被委派给BusinessUnit 来读取存储介质中的记录.

AOP就是定义一些切入点(pointcut)和处理方法(advice).一个”切入点”是源代码中一个执行点.前面的例子定义了一个”切入点” — 类 BusinessUnitService中的findBusinessUnits方法.一个”处理方法”顾名思义就是当执行到某个”切入点”时的一块代 码.类BusinessUnitPersistentAspect 包括advice方法findAllBusinessUnits,该方法从存储介质中载入数据,然后使用工厂类创建BusinessUnit 对象.然后这个对象被加入map,map对象的引用通过 BusinessUnitService 对象获得.”切入点”和”处理方法”组成了所谓的”aspect”.

为了读取存储介质中的数据,OOP方法通过一个DAO类来做.而AOP中,你只要定义一个”切入点”和相应的”处理方法”来读取数据.AOP框架会以advice的形式注入代码,既可以在执行期也可以在编译期.

总而言之,当类BusinessUnitService 中的findAllBusinessUnits 方法被调用时,AOP框架会在”切入点”处注入处理方法,通过BusinessUnit 对象预先读取数据来填充map对象.这样,持久层方面的代码就可以移到业务代码之外了.

新方法里的”Aspect”

本节讨论如何用AOP为应用程序的各个”切面”建模

操作资源

类BusinessUnitPersistenceAspect 的持久方法使用了一个buffered reader.你甚至可以定义”切面”的”切面”,但为了简单,这里只关注类的查找方法.

1.
2. @Aspect(“perJVM”)
3. public class BufferedFileReaderAspect {
4.
5. @Expression(“execution(* org.javatechnocrats.aop.withaop.aspects.BusinessUnitPersistenceAspect.find*(..))”)
6. Pointcut businessUnitPersistenceAspect;
7.
8. // 其他”切入点”定义
9.
10. @Expression(“businessUnitPersistenceAspect ||
11. employeePersistenceAspect ||
12. managerPersistenceAspect”)
13. Pointcut allPersistencePointcuts;
14.
15. private Map<Class, String> fileNames;
16.
17. public BufferedFileReaderAspect() {
18. System.out.println(“BufferedFileReaderAspect created”);
19. fileNames = new HashMap<Class, String>();
20. fillFileNames();
21. }
22.
23. @Before(“allPersistencePointcuts”)
24. public void assignReader(JoinPoint joinPoint) throws Throwable {
25. System.out.println(“assignReader advice called”);
26. Object callee = joinPoint.getCallee();
27. IBufferedFileReaderConsumable bufReaderConsumable = (IBufferedFileReaderConsumable)callee;
28. Class persistenceClass = callee.getClass();
29. String fileName = fileNames.get(persistenceClass);
30. FileReader fileReader = new FileReader(fileName);
31. BufferedReader bufferedReader = new BufferedReader(fileReader);
32. bufReaderConsumable.setBufferedReader(bufferedReader);
33. }
34.
35. @AfterFinally(“allPersistencePointcuts”)
36. public void releaseReader(JoinPoint joinPoint) throws Throwable {
37. //释放buffered reader等资源
38. }
39. //其他方法
40. }

上面的代码试图为每一个方法创建”切入点”– 所有以find开头的方法.无论何时这些方法被调用,assignReader方法都会被提前执行.这里它获取被调用的类实例然后设置新建的BufferedReader.

同样地,在releaseReader 方法里,代码会预先关闭buffered reader集合.本节只解释@before和@
AfterFinally 这两个”切入点”.(以J2SE 5.0的标记定义).另外,你也可以在方面定义的xml文件中声明他们.你可以查看例程源代码中的aop.xml文件.

下载

持久化

前面提到,OOP方法使用BusinessUnit 来为应用的持久层填充Map.在下面的高亮代码中(@before一行,以及while循环代码 – 译者注),当BusinessUnitService 中的方法findAllBusinessUnits 被调用时”处理方法 “findAllBusinessUnits 也将被调用.

1.
2. @Aspect(“perJVM”)
3. public class BusinessUnitPersistenceAspect implements IBufferedFileReaderConsumable {
4.
5. private BufferedReader buffFileReader;
6.
7. @Before(“execution(Collection org.javatechnocrats.aop.withaop.BusinessUnitService.findAllBusinessUnits())”)
8. public void findAllBusinessUnits(JoinPoint joinPoint) throws Throwable {
9. System.out.println(“findAllBusinessUnits advice called”);
10. Map<String, BusinessUnit> businessUnits =
11. ((BusinessUnitService)joinPoint.getThis()).getBusinessUnits();
12. String businessUnitRecord;
13. while((businessUnitRecord = buffFileReader.readLine()) != null) {
14. BusinessUnit businessUnit = BusinessUnitFactory.createBusinessUnit(businessUnitRecord);
15. businessUnits.put(businessUnit.getId(), businessUnit);
16. }
17. }
18.
19. public void setBufferedReader(BufferedReader buffFileReader) {
20. System.out.println(“BusinessUnitPersistenceAspect.setBufferedReader called”);
21. this.buffFileReader = buffFileReader;
22. }
23.
24. public BufferedReader getBufferedReader() {
25. System.out.println(“BusinessUnitPersistenceAspect.getBufferedReader called”);
26. return this.buffFileReader;
27. }
28. }

“处理方法”从数据存储中读取记录,使用工厂类创建一个BusinessUnit实例.然后这个实例被加入到Map.该Map掌管程序的所有持久化”aspect”.

日志
本文中的例子没有包含一个完整的日志AOP解决方案.但是,它为java.lang.Object类的toString方法定义了一个”切入点”来获取类 的调试信息.因此,域中的类不需要实现toString方法.通常情况下你可能需要为每一个类都要实现toString方法.

1.
2. @Aspect(“perJVM”)
3. public class LoggingAspect {
4.
5. @Around(“execution(String org.javatechnocrats.aop.withaop..*.toString())”)
6. public Object toStringAdvice(JoinPoint joinPoint) throws Throwable {
7. System.out.println(“toStringAdvice called”);
8. String toString = (String)joinPoint.proceed();
9. Object target = joinPoint.getThis();
10. Field fields[] = target.getClass().getDeclaredFields();
11. List members = new ArrayList(fields.length + 1);
12. members.add(toString);
13. for(Field field : fields) {
14. field.setAccessible(true);
15. Object member = field.get(target);
16. members.add(field.getName() + “=” + member);
17. }
18. return members.toString();
19. }

你也可以用这个样例代码完成错误处理”切面”.

深入源代码

为了理解样例需求的OOP设计,请参看源代码并思考以下几个问题:
下载

* 首先分析oldway包中EmployeeServiceTestCase 类中的代码
* 查看testEmployeeCredit 方法
* 搞懂业务类Employee和BusinessUnit
* 学习 service,repository和factory这些概念.这些是业务驱动设计的主要概念.
* 更深入地理解oldway包中的service,repository和factory类

而AOP地理解则应该是:
* 分析newway包中EmployeeServiceTestCase 类
* 查看service,repository和factory类,基本和前一种差不多.只是你要让”处理方法”截获程序的执行流程.
* 研究aspect类学习”切入点”的定义

要执行程序,你需要做的工作:
* 下载AspectWerkz 2.0 http://aspectwerkz.codehaus.org/
* 设置以下的环境变量:
set JAVA_HOME=c:Program FilesJavajdk1.5.0
set ASPECTWERKZ_HOME=C:aw_2_0_2
set PATH=%PATH%;%ASPECTWERKZ_HOME%bin
set CLASSPATH=
C:aw_2_0_2libaspectwerkz-2.0.RC2.jar;C:aw_2_0_2libaspectwerkz-jdk5-2.0.RC2.jar; classes;C: junit3.8.1resourceslibjunit.jar
* 解压缩源代码和其他文件
* 编译Java文件,但不要编译测试用例否则你调试时会遇到一个错误.
* 进行离线调试.假设你把文件解压缩到c:aop ,类文件解压到c:aopclasses,在c:aop目录下执行以下命令:
% ASPECTWERKZ_HOME%binaspectwerkz -offline etc/aop.xml -cp classes classes
* AOP框架会修改类来注入必要的字节码
* 编译测试用例,使用JUnit运行它.

后记
当你完成了上面的这些工作,你应该有以下的领悟:
* 程序中的交叉关联
* 关于AOP中”切面”的含义
* 如何用AOP来把程序业务层中的交叉关联分离出来,使用”切入点”和”处理方法”
* OOP和AOP时在程序控制流上的不同

从本文你应该也得到一种看待实际开发的新视角.你应该有信心使用AOP来改进项目中的设计,建模,提高代码的重用性.至少,你可以开始使用AOP来处理日志,错误和持久化.

个人觉得,AOP的学习曲线相对较陡,尤其在理解定义”切入点”的句法时.理想的情况是,使用OOP来设计业务模型,使用AOP把业务模型中的交叉关联移出,从而使代码简洁并提高可读性.

AOP的一个缺点是会使调试变得困难,因为不同于OOP,程序流变的复杂了,交互是由编译期或执行期决定.我准备将来做一些自动化工具来解决这个问题.