使用 aspectj 的银行账户程序
bank account program using aspectj
我想编写一个 java 程序来跟踪银行账户
现在我有以下简单的程序:
public class account
{
private double balance;
private String owner;
public account(double x, String s) { balance=x; owner=s; }
public String owner() { return owner; }
public void withdraw(double a) { balance -= a; }
public void deposit(double a) { balance += a; }
public void printbalance() { System.out.println(balance); }
// main for testing:
public static void main(String[] argv)
{
account a1 = new account(2000,"you boss");
account a2 = new account(1000,"me nerd");
a1.deposit(400);
a2.withdraw(300000); // not enough money!
a2.withdraw(-500000); // trying to cheat!
a1.printbalance();
a2.printbalance();
}//main
} // account
我想使用 aspectj 添加到这个程序中:
1-我想防止账户从当前余额中提取更大的金额,提取负数。
2-我也想要它来防止存入负数。
3-我需要添加一个图形界面,(按钮)
4- 添加客户进行交易前需要输入的密码。
5- 跟踪帐户上的所有交易(取款和存款),并在需要时打印报告。
非常感谢您的帮助。谢谢。
privileged aspect newAccount
{
//withdraw (prevent withdraw negative numbers and number greater than the //current balance)
void around(account a, double x) : execution(void account.withdraw(double)) && target(a) && args(x){
if(x > a.balance){
System.out.println("not enough money!");
return;
}else if(x < 0){
System.out.println("trying to cheat!");
return;
}
proceed(a, x);
}
//Deposit: prevent deposit negative number
void around(double x) : execution(void account.deposit(double)) && args(x){
if(x < 0){
System.out.println("trying to deposit negtive money!");
return;
}
proceed(x);
}
after() : execution(public static void *.main(String[])){
account.a3 = new account(3000,"he nerd");
a3.deposit(-100);
a3.printbalance();
}
//To Do: pin secret password
//To Do: Transaction Record
}
我看你还在学习Java因为你不知道诸如此类的基本编程约定
- class 名称应以大写字母开头,
- 变量、参数和字段的名称应该易于理解,而不是单个字母。
您还从特权方面使用直接字段访问,而不是仅仅为您的 class 字段创建 public getter 方法并使用它们。 toString
方法也很有用,因为这样您就可以轻松打印对象,而无需访问 getters 并制作您自己的输出。
此外,main
方法之后的建议 运行 是一个很好的实验,但没有多大意义。因为帐户所有者与您的应用程序中的其中一位帐户所有者同名,所以您似乎想黑入该帐户。我在那里评论了代码,以解释为什么它不能那样工作。
我还重构了您的应用程序 class 和方面,现在看起来像这样而不改变功能:
package de.scrum_master.app;
public class Account {
private String owner;
private double balance;
public Account(String owner, double balance) {
this.owner = owner;
this.balance = balance;
}
public void withdraw(double amount) {
balance -= amount;
}
public void deposit(double amount) {
balance += amount;
}
public String getOwner() {
return owner;
}
public double getBalance() {
return balance;
}
@Override
public String toString() {
return "Account[owner=" + owner + ", balance=" + balance + "]";
}
public static void main(String[] argv) {
Account bossAccount = new Account("Boss", 2000);
Account nerdAccount = new Account("Nerd", 1000);
bossAccount.deposit(400);
nerdAccount.withdraw(200);
bossAccount.withdraw(300000); // Cannot withdraw more than account balance
nerdAccount.withdraw(-500000); // Cannot withdraw a negative amount
bossAccount.deposit(-123456); // Cannot deposit a negative amount
System.out.println(bossAccount);
System.out.println(nerdAccount);
}
}
package de.scrum_master.aspect;
import de.scrum_master.app.Account;
public aspect AccountAspect {
// Withdrawal
void around(Account account, double amount) :
execution(void Account.withdraw(double)) &&
target(account) &&
args(amount)
{
if (amount > account.getBalance()) {
System.out.println("Cannot withdraw more than account balance");
return;
}
if (amount < 0) {
System.out.println("Cannot withdraw a negative amount");
return;
}
proceed(account, amount);
}
// Deposit
void around(double amount) :
execution(void Account.deposit(double)) &&
args(amount)
{
if (amount < 0) {
System.out.println("Cannot deposit a negative amount");
return;
}
proceed(amount);
}
// This does not make any sense because
// 1. it happens after the application ends (after leaving main method)
// 2. Even though the account owner is the same as in the main method,
// it does not mean that by creating a new object with the same name
// the "Nerd" can manipulate the original account balance. You have to
// intercept the original Account object and manipulate it directly.
after() : execution(public static void *.main(String[])) {
System.out.println("--- after end of main program ---");
Account account = new Account("Nerd", 3000);
account.deposit(-100);
System.out.println(account);
}
// TODO: PIN secret password
// TODO: transaction record
}
控制台日志将是:
Cannot withdraw more than account balance
Cannot withdraw a negative amount
Cannot deposit a negative amount
Account[owner=Boss, balance=2400.0]
Account[owner=Nerd, balance=800.0]
--- after end of main program ---
Cannot deposit a negative amount
Account[owner=Nerd, balance=3000.0]
我不会给你做作业,但给你一些提示:
PIN(密码):Account
class 需要一个可以在构造函数中设置的字段 pin
并且不应该有 public getter 方法以避免任何人都可以访问 PIN。如果作业要求您不编辑基础 class 而是通过 AOP 解决问题,则可以使用类型间定义 (ITD) 来添加私有字段和 public setter,甚至可能是 class 的附加构造函数。接下来,您将添加一条建议,如果用户首次尝试访问某个帐户的任何交易方法,例如 deposit
和 withdraw
,则要求用户在控制台上输入 PIN。正确输入 PIN 后,他就可以继续,否则会出现错误消息,交易将被禁止。方面本身可以保留所有 Account
对象的缓存(临时存储) - 可能你想使用 Set<Account>
- 在 运行 会话期间已成功验证,以避免用户必须再次输入同一帐户的 PIN。
每个帐户的交易记录:同样,您可以使用 ITD 将类似 List<TransactionRecord>
的内容作为字段添加到 Account
,用空列表对其进行初始化然后为每笔存款或取款添加交易记录。您还可以保持简单的概念证明,而不是创建 TransactionRecord
助手 class,而只是使用 List<Double>
进行交易,记录存款的正数和取款的负数。带有 "deposit 123.45" 或 "withdrawal 67.89" 等元素的 List<String>
也是一个可行的替代方案。重要的是你的老师可以看到正确的方面逻辑。
我想编写一个 java 程序来跟踪银行账户
现在我有以下简单的程序:
public class account
{
private double balance;
private String owner;
public account(double x, String s) { balance=x; owner=s; }
public String owner() { return owner; }
public void withdraw(double a) { balance -= a; }
public void deposit(double a) { balance += a; }
public void printbalance() { System.out.println(balance); }
// main for testing:
public static void main(String[] argv)
{
account a1 = new account(2000,"you boss");
account a2 = new account(1000,"me nerd");
a1.deposit(400);
a2.withdraw(300000); // not enough money!
a2.withdraw(-500000); // trying to cheat!
a1.printbalance();
a2.printbalance();
}//main
} // account
我想使用 aspectj 添加到这个程序中:
1-我想防止账户从当前余额中提取更大的金额,提取负数。
2-我也想要它来防止存入负数。
3-我需要添加一个图形界面,(按钮)
4- 添加客户进行交易前需要输入的密码。
5- 跟踪帐户上的所有交易(取款和存款),并在需要时打印报告。
非常感谢您的帮助。谢谢。
privileged aspect newAccount
{
//withdraw (prevent withdraw negative numbers and number greater than the //current balance)
void around(account a, double x) : execution(void account.withdraw(double)) && target(a) && args(x){
if(x > a.balance){
System.out.println("not enough money!");
return;
}else if(x < 0){
System.out.println("trying to cheat!");
return;
}
proceed(a, x);
}
//Deposit: prevent deposit negative number
void around(double x) : execution(void account.deposit(double)) && args(x){
if(x < 0){
System.out.println("trying to deposit negtive money!");
return;
}
proceed(x);
}
after() : execution(public static void *.main(String[])){
account.a3 = new account(3000,"he nerd");
a3.deposit(-100);
a3.printbalance();
}
//To Do: pin secret password
//To Do: Transaction Record
}
我看你还在学习Java因为你不知道诸如此类的基本编程约定
- class 名称应以大写字母开头,
- 变量、参数和字段的名称应该易于理解,而不是单个字母。
您还从特权方面使用直接字段访问,而不是仅仅为您的 class 字段创建 public getter 方法并使用它们。 toString
方法也很有用,因为这样您就可以轻松打印对象,而无需访问 getters 并制作您自己的输出。
此外,main
方法之后的建议 运行 是一个很好的实验,但没有多大意义。因为帐户所有者与您的应用程序中的其中一位帐户所有者同名,所以您似乎想黑入该帐户。我在那里评论了代码,以解释为什么它不能那样工作。
我还重构了您的应用程序 class 和方面,现在看起来像这样而不改变功能:
package de.scrum_master.app;
public class Account {
private String owner;
private double balance;
public Account(String owner, double balance) {
this.owner = owner;
this.balance = balance;
}
public void withdraw(double amount) {
balance -= amount;
}
public void deposit(double amount) {
balance += amount;
}
public String getOwner() {
return owner;
}
public double getBalance() {
return balance;
}
@Override
public String toString() {
return "Account[owner=" + owner + ", balance=" + balance + "]";
}
public static void main(String[] argv) {
Account bossAccount = new Account("Boss", 2000);
Account nerdAccount = new Account("Nerd", 1000);
bossAccount.deposit(400);
nerdAccount.withdraw(200);
bossAccount.withdraw(300000); // Cannot withdraw more than account balance
nerdAccount.withdraw(-500000); // Cannot withdraw a negative amount
bossAccount.deposit(-123456); // Cannot deposit a negative amount
System.out.println(bossAccount);
System.out.println(nerdAccount);
}
}
package de.scrum_master.aspect;
import de.scrum_master.app.Account;
public aspect AccountAspect {
// Withdrawal
void around(Account account, double amount) :
execution(void Account.withdraw(double)) &&
target(account) &&
args(amount)
{
if (amount > account.getBalance()) {
System.out.println("Cannot withdraw more than account balance");
return;
}
if (amount < 0) {
System.out.println("Cannot withdraw a negative amount");
return;
}
proceed(account, amount);
}
// Deposit
void around(double amount) :
execution(void Account.deposit(double)) &&
args(amount)
{
if (amount < 0) {
System.out.println("Cannot deposit a negative amount");
return;
}
proceed(amount);
}
// This does not make any sense because
// 1. it happens after the application ends (after leaving main method)
// 2. Even though the account owner is the same as in the main method,
// it does not mean that by creating a new object with the same name
// the "Nerd" can manipulate the original account balance. You have to
// intercept the original Account object and manipulate it directly.
after() : execution(public static void *.main(String[])) {
System.out.println("--- after end of main program ---");
Account account = new Account("Nerd", 3000);
account.deposit(-100);
System.out.println(account);
}
// TODO: PIN secret password
// TODO: transaction record
}
控制台日志将是:
Cannot withdraw more than account balance
Cannot withdraw a negative amount
Cannot deposit a negative amount
Account[owner=Boss, balance=2400.0]
Account[owner=Nerd, balance=800.0]
--- after end of main program ---
Cannot deposit a negative amount
Account[owner=Nerd, balance=3000.0]
我不会给你做作业,但给你一些提示:
PIN(密码):
Account
class 需要一个可以在构造函数中设置的字段pin
并且不应该有 public getter 方法以避免任何人都可以访问 PIN。如果作业要求您不编辑基础 class 而是通过 AOP 解决问题,则可以使用类型间定义 (ITD) 来添加私有字段和 public setter,甚至可能是 class 的附加构造函数。接下来,您将添加一条建议,如果用户首次尝试访问某个帐户的任何交易方法,例如deposit
和withdraw
,则要求用户在控制台上输入 PIN。正确输入 PIN 后,他就可以继续,否则会出现错误消息,交易将被禁止。方面本身可以保留所有Account
对象的缓存(临时存储) - 可能你想使用Set<Account>
- 在 运行 会话期间已成功验证,以避免用户必须再次输入同一帐户的 PIN。每个帐户的交易记录:同样,您可以使用 ITD 将类似
List<TransactionRecord>
的内容作为字段添加到Account
,用空列表对其进行初始化然后为每笔存款或取款添加交易记录。您还可以保持简单的概念证明,而不是创建TransactionRecord
助手 class,而只是使用List<Double>
进行交易,记录存款的正数和取款的负数。带有 "deposit 123.45" 或 "withdrawal 67.89" 等元素的List<String>
也是一个可行的替代方案。重要的是你的老师可以看到正确的方面逻辑。