由于Spring2的AOP部分作了比較大的調整,很多地方的使用引入了AspectJ中的內容,為了完成《深入Spring 2:輕量級J2EE開發框架原理與實踐》中Spring AOP應用一章的寫作,因此這兩天把AspectJ研究了一下,重讀了一次《AspectJ in action》,受益不少。這里是前幾天做的一個回合格斗戲示例:
這個示例中有一個設計了一個戰士Soldier類,這個類具有一些隨機功能,包括發動攻擊、治療、躲避、移動等功能。另外有一個簡單的主程序MainTest,里面的功能就是讓兩個戰士回合制互相攻擊。另外有一個切面,是用來觀察并輸入戰斗的詳細過程,直到一個被打倒下:
?
? 先看戰士Soldier的代碼:
package springroad.demo.chap5.aspectj;
public class Soldier {
private String name;
private int health=100;
private int damage=10;
private int x=10;
private int y=10;
public boolean attack(Soldier target){
?boolean ret=false;
?if(!target.dodge())
?{
??target.setHealth(target.getHealth()-this.damage);
??ret=true;
?}
?move();
?treat();?
?return ret;
}
public void move()
{
?this.x+=getRandom(5);
?this.y+=getRandom(5);
}
//躲避x及y隨機變動,成功率為50%
public boolean dodge()
{
?return getRandom(10)%2==0;
}
//治療,具有一定成功的機會,可以提高生命值0-20點
public void treat()
{
?if(canTreat())
??this.health+=getRandom(20);
}
public boolean canTreat()
{
?return getRandom(10)/2==0;
}
private int getRandom(int seed)
{
?return RandomUtil.getRandomValue(seed);
}
//getter及setter方法
public int getHealth() {
?return health;
}
public void setHealth(int health) {
?this.health = health;
}
public String getName() {
?return name;
}
public void setName(String name) {
?this.name = name;
}
public int getX() {
?return x;
}
public void setX(int x) {
?this.x = x;
}
public int getY() {
?return y;
}
public void setY(int y) {
?this.y = y;
}
public int getDamage() {
?return damage;
}
public void setDamage(int damage) {
?this.damage = damage;
}
}
?
?
再看看MainTest.java中戰場模擬的代碼(即主程序):
package springroad.demo.chap5.aspectj;
public class MainTest {?
?public static void main(String[] args) {
?Soldier p1=new Soldier();
?p1.setName("角色1");
?Soldier p2=new Soldier();
?p2.setName("角色2");
?int i=0;
?while(p1.getHealth()>0 && p2.getHealth()>0)
?{
??p2.attack(p1);
??p1.attack(p2);
??i+=2;
?}?
?System.out.println("戰斗次數:"+i);
?if(p1.getHealth()>0)System.out.println(p1.getName()+"戰勝!");
?else System.out.println(p2.getName()+"戰勝!");
?}
}
?
隨機數生成器(概率產生)
package springroad.demo.chap5.aspectj;
public class RandomUtil {
private static java.util.Random random=new java.util.Random();
public static int getRandomValue(int seed)
{
?return random.nextInt(seed);
}
}
?
這上面三個程序是完整的,可以直接用javac編譯,然后執行MainTest,我們可以看到經過一小段時間戰斗后分出勝負后,會顯示出戰斗的次數及勝負情況。
為了要能觀察整個戰斗的詳細過程,這里在不改動上面的程序代碼的情況下,使用AspectJ做了一個切面,主要用來輸出攻擊的情況。
?
切面RecordGame.aj的代碼如下 :
?
package springroad.demo.chap5.aspectj;
public aspect RecordGame {
?private static java.text.SimpleDateFormat df=new java.text.SimpleDateFormat("yyyy-MM-dd H:m:s");
?pointcut doRecord():execution(boolean Soldier.attack(Soldier));?
?pointcut? supperRole(Soldier s): target(s)&&execution(boolean Soldier.canTreat());?
?after() returning(boolean value) :doRecord()
?{
??Soldier s=(Soldier)thisJoinPoint.getTarget();?
??Soldier t=(Soldier)thisJoinPoint.getArgs()[0];
??System.out.println(df.format(new java.util.Date())+":"+s.getName()+" 向 "+t.getName()+" 發動了一次攻擊!--結果:"+(value?"成功":"失敗"));
??System.out.println(s.getName()+"生命值:"+s.getHealth()+";"+t.getName()+"生命值:"+t.getHealth());
?}
?after(Soldier s)returning(boolean value):target(s)&&call(boolean Soldier.canTreat())
?{
??if(value)System.out.println(s.getName()+"得到治療!");
?}
?boolean around(Soldier s): supperRole(s)
?{
??? if("super".equals(s.getName())) return true;
??? else return proceed(s);
?}
?}
?
使用ajt編譯上面的四個文件,在命令行輸入如下所示命令(要求AspectJ正確安裝及配置):
ajc springroad\demo\chap5\*.*j*
?
然后再使用java 命令執行MainTest即可以看到非常有趣的結果(多執行幾次試試)。如下圖所示:
?

另外,切面中還定義了一個超級角色,也即名稱為“super”的戰士,你把客戶端某個戰士的名稱改成super,然后再運行試試,90%的情況都是super勝。
(本文作者:
EasyJF開源團隊??
大峽 轉載請保留作者聲明,謝謝!)
posted on 2006-10-30 16:20
簡易java框架 閱讀(1447)
評論(1) 編輯 收藏