Я вижу, что вы все еще изучаете Java, потому что вы не знаете базовых c соглашений о программировании, таких как
- имена классов должны начинаться с заглавной буквы,
- переменные, параметры и поля должны иметь понятные имена, а не отдельные буквы.
Вы также используете прямой доступ к полям из привилегированного аспекта, вместо того, чтобы просто создавать методы getli publi c для поля вашего класса и их использование. Метод toString
также полезен, потому что тогда вы можете легко напечатать объект, не обращаясь к геттерам и не создавая собственный вывод.
Кроме того, совет, выполняемый после метода main
, является хорошим экспериментом, но не делает имеет смысл. Поскольку владелец учетной записи имеет то же имя, что и один из владельцев учетной записи в вашем приложении, похоже, что вы хотите взломать эту учетную запись. Я прокомментировал код там, чтобы объяснить, почему он не может так работать.
Я также реорганизовал и класс приложения, и аспект, чтобы он теперь выглядел так, без изменения функциональности:
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
необходимо поле pin
, которое можно установить в конструкторе, и не должно иметь метода получения publi c, чтобы никто не мог получить доступ к PIN-коду. Если назначение требует, чтобы вы не редактировали базовый класс, а решали проблему через AOP, вы можете использовать определение между типами (ITD), чтобы добавить приватное поле и установщик publi c, возможно, даже дополнительный конструктор к учебный класс. Затем вы добавите совет, в котором пользователю будет предложено ввести PIN-код на консоли, если он впервые попытается получить доступ к каким-либо транзакционным методам, таким как deposit
и withdraw
определенной учетной записи. После правильного ввода PIN-кода он сможет продолжить, в противном случае появится сообщение об ошибке и транзакция будет запрещена. Сам аспект может хранить кэш (временное хранилище) всех Account
объектов - вероятно, вы хотите использовать Set<Account>
- которые были успешно аутентифицированы во время сеанса работы, чтобы пользователь не вводил PIN-код. снова для той же учетной записи.
Запись транзакции для учетной записи: Опять же, вы можете использовать ITD, чтобы добавить что-то вроде List<TransactionRecord>
в качестве поля к Account
, инициализировать его с пустым списком, а затем добавьте запись транзакции для каждого пополнения или снятия. Вы также можете сделать это простым для подтверждения своей концепции, не создавая вспомогательный класс TransactionRecord
, а просто используя List<Double>
для транзакций, записывая положительные суммы для депозитов и отрицательные для снятия. A List<String>
с такими элементами, как «депозит 123,45» или «вывод 67,89», также является приемлемой альтернативой. Важно то, что ваш учитель может видеть правильный аспект логики c.