The task:
There is an AccountManager
that makes transfers. It receives 2 arrays of the same size: accounts and sums. They need to be transferred to the accounts correspondingly.
public interface AccountManager {
public boolean transfer(Account[] accounts, int[] deltas);
}
There is also an Account
interface
:
public interface Account {
public void change(int delta) throws TryAgainException, BlockAccountException;
}
If change()
throws TryAgainException
, we just need to repeat the transfer operation. If change()
throws BlockAccountException
, we need to roll back the transfer operation. That is, reverse all changes to previous accounts.
AccountClass
public class AccountClass implements Account {
// setting initial value to 100. so that account would not be empty
private int accountNum;
private int currentAccount = 100;
public AccountClass(int accountNum) {
this.accountNum = accountNum;
}
@Override
public void change(int delta) throws TryAgainException,
BlockAccountException {
System.out.println("account before change" + toString());
int newBalance = getCurrentAccount() + delta;
if (newBalance < 0) {
throw new BlockAccountException(
"money cannot be withdrawn as balance will be negative");
} else if (delta == 100) {
throw new TryAgainException();
}
setCurrentAccount(getCurrentAccount() + delta);
System.out.println("account after change" + toString());
}
public int getCurrentAccount() {
return currentAccount;
}
@Override
public String toString() {
return "Account" + accountNum + " [currentAccount=" + currentAccount + "]";
}
// making setter private so it will be impossible to modify account from
// outside
private void setCurrentAccount(int currentAccount) {
this.currentAccount = currentAccount;
}
AccountManagerClass
public class AccountManagerClass implements AccountManager {
@Override
public boolean transfer(Account[] accounts, int[] deltas) {
for (int i = 0; i < accounts.length; i++) {
int tryNum = 0;
while (true) {
try {
accounts[i].change(deltas[i]);
break;
} catch (TryAgainException e) {
tryNum++;
if (tryNum == 5) {
break;
}
System.out.println("trying again");
} catch (BlockAccountException e) {
// rollback
System.out.println(e.getMessage());
System.out.println("rolling back");
if (i > 0) {
for (int j = i - 1; j >= 0; j--) {
try {
accounts[j].change(-deltas[j]);
} catch (TryAgainException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (BlockAccountException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
return false;
}
}
}
return true;
}
Main
public class Main {
public static void main(String[] args) {
AccountManagerClass accountManagerClass = new AccountManagerClass();
Account[] accounts = {new AccountClass(1), new AccountClass(2), new AccountClass(3), new AccountClass(4)};
int[] deltas = {100, 200, -200, 99};
accountManagerClass.transfer(accounts, deltas);
}
}
-
1\$\begingroup\$ Usually its the responsibility of a database transaction. Can you use database transactions? \$\endgroup\$Grim– Grim2015年08月17日 14:09:15 +00:00Commented Aug 17, 2015 at 14:09
-
\$\begingroup\$ Is concurrency a requirement, or just something nice to consider in your codebase? \$\endgroup\$h.j.k.– h.j.k.2015年08月17日 14:45:06 +00:00Commented Aug 17, 2015 at 14:45
-
\$\begingroup\$ It's extremely weird to fix a starting account balance to 100, unless this is part of an exercise and indicated as such... we're not in Monopoly here... \$\endgroup\$h.j.k.– h.j.k.2015年08月17日 14:46:14 +00:00Commented Aug 17, 2015 at 14:46
-
\$\begingroup\$ sorry, i should've mention, yes it is an exercise not a real case \$\endgroup\$rigby– rigby2015年08月17日 15:14:38 +00:00Commented Aug 17, 2015 at 15:14
1 Answer 1
// making setter private so it will be impossible to modify account from
// outside
private void setCurrentAccount(int currentAccount) {
this.currentAccount = currentAccount;
}
So, what's the point of this setter at all? :)