/* * Account.java * * Created on August 14, 2002, 1:18 PM * originally created on March 6, 2002, 12:45 PM */ package bank; //import IO.RedmondMsgIn; import IDs.Id; import SortSearchEtc.Sorts; import java.util.Random; import java.util.Arrays; // don't have to import exception class NegativeAmount because it is in the same // package /** * * @author Mike Redmond * @version 1 * Simple Bank Account */ public class Account implements Comparable, Cloneable { // Comparable is an interface - don't show until we talk about them // making account comparable enables sorting them protected Id acctNum; // use Id class so get check digits and stuff like that protected String PIN; protected double balance = 0; // protected double intRate = 0.03; /** * Creates a new instance of Account * takes defaults for balance (0) and interest rate, but no value for acct number */ public Account() { } /** * Creates a new instance of Account - with random acct number * and other given info about the account */ public Account(String pin, double bal) { String numb = Id.genRandomValidId(); // but what length? and do we want a check digit? // in Java, the Id, being an object, is not automatically created when the account // is being created (I believe in C++ it would exist starting when the constructor started // (after the base member initialization list has "run")) acctNum = new Id(numb); //acctNum.setId(numb); // add a check digit acctNum.addCheckDigit(); // don't need the returned check digit PIN = pin; balance = bal; } /** * Creates a new instance of Account - given info about the account */ public Account(String acct, String pin, double bal) { // in Java, the Id, being an object, is not automatically created when the account // is being created (I believe in C++ it would exist starting when the constructor started // (after the base member initialization list has "run")) acctNum = new Id(acct); //acctNum.setId(acct); PIN = pin; balance = bal; } /** * deposit a given amount into the calling Account */ public boolean deposit(double amt) { // reject a negative deposit // only return false because we don't know where the amount came // from. it might not have come from a user, so we don't know if // we should reprompt (let caller handle the problem) if (amt <= 0) { System.out.println("PROGRAM ERROR - cannot deposit negative amount"); return false; } else { // Updates the account balance and returns true if successful balance = balance + amt; return true; } } /** * deposit a given amount into the calling Account * returns the new balance * Exception Handling version - do not show until exception handling covered */ public double depositEx (double amt) throws NegativeAmount { // reject a negative deposit // only throw exception because we don't know where the amount came // from. it might not have come from a user, so we don't know if // we should reprompt (let caller handle the problem) // or even really whether it is reasonable to put a message out - might be // a program error instead of a user error // using exception handling allows us to return the new balance when things // are ok. Before, I was forced to choose between having a boolean return or a balance if (amt <= 0) { throw new NegativeAmount("PROGRAM ERROR - cannot deposit negative amount",amt); } else { // Updates the account balance and returns true if successful balance = balance + amt; return balance; } } /** * withdraw a given amount from the calling Account */ public boolean withdraw(double amt) { // reject a negative wothdrawal // only return false because we don't know where the amount came // from. it might not have come from a user, so we don't know if // we should reprompt (let caller handle the problem) if (amt <= 0) { System.out.println("PROGRAM ERROR - cannot withraw a negative amount"); return false; } // reject a withdrawal larger than account balance else if (amt > balance) { System.out.println("ERROR - cannot withraw an amount more than in account"); return false; } else { // can withdraw balance = balance - amt; return true; } } /////////////////////////////////////////////////////////////////// // Inspectors /////////////////////////////////////////////////////////////////// /** * return the current balance - basically an account inquiry */ public double getBal() { return balance; } /** * return the account number as a string */ public String getAcctNum() { return acctNum.getId(); } /** * return the account number as an ID */ public Id getAcctID() { return acctNum; } /** * report the PIN */ public String getPin() { return PIN; } /////////////////////////////////////////////////////////////////// // Mutators /////////////////////////////////////////////////////////////////// /** * set the account balance - should probably only be used publicly * at the creation of the account. All other accesss to changing * the balance should be handled through deposit or withdraw */ public boolean setBal(double amt) { // reject negative balance if (amt < 0) { System.out.println("PROGRAM ERROR - cannot set a negative account balance"); return false; } else { balance = amt; } return true; } /** * set account number, given an id - should probably only be used publically * at the creation of the account. */ public boolean setAcctId(Id acctNumber) { acctNum = acctNumber; // could check acct number to see if it is valid (check digit // - or already in DB) but for now just say that it is ok return true; } /** * set account number, given a string - should probably only be used publically * at the creation of the account. */ public boolean setAcctNum(String acctNumber) { acctNum.setId(acctNumber); // could check acct number to see if it is valid (check digit // - or already in DB) but for now just say that it is ok return true; } /** * set PIN - should be carefully controlled */ public boolean setPIN(String pin) { PIN = pin; // could check PIN based on some PIN rules - but for now just say // that it is ok return true; } /** * determine if a passed string is the correct account number for the * calling object */ public boolean matchAcctNum(String toCompare) { if (acctNum.getId().equals(toCompare)) { return true; } else { return false; } } /** * determine if a passed account has the same account number as the * calling object * (does not worry about whether the id matches on required length or * whether there is a check digit - if the string matches, this matches */ public boolean matchAcctNum(Account toCompare) { if (acctNum.getId().equals(toCompare.getAcctNum())) { return true; } else { return false; } } /** * determine if a passed account has the same contents as the * calling object (account number, PIN, AND balance) * Overrides version in java.lang.Object */ public boolean equals(Account toCompare) { if ( acctNum.getId().equals(toCompare.getAcctNum()) && PIN.equals(toCompare.getPin()) && balance == toCompare.getBal() ) { return true; } else { return false; } } /** * produce a string for an account - generally used for display * Overrides version in java.lang.Object */ public String toString() { String res = "Acct: " + acctNum.getId() + " PIN: " + PIN + " Bal: " + balance; return res; } /** * Compares two accounts - needed for sorting - required since implements Comparable interface * Don't show until we cover interfaces * returns negative if object comparing to is less, zero if object comparing to is equal, * positive if object comparing to is greater * MAR - I have made the call that accounts should be compared based on their acct number */ public int compareTo(Object obj) { // convert the passed object to an Account\ Account other = (Account) obj; // pull out the ids Id otherId = other.getAcctID(); Id firstId = getAcctID(); // make an object based on the otherId Object otherObj = (Object) otherId; // do the comparison using Id class's capabilities (compareTo) // and return the result return firstId.compareTo(otherObj); } /** * overrides clone() in Object - does deeper copy * Also, by declaring this to be public, this opens up access to cloning * Account objects, so it can be done by any class */ /* public Object clone() throws CloneNotSupportedException { Account res = new Account(); // create a brand new object String acct = getAcctNum(); // get the String for the ID res.acctNum = new Id(acct); // create a new ID using the string res.PIN = new String(this.PIN); // create a new PIN using old one res.balance = balance; return (Object) res; // cast back to Object before return to meet requirements } **/ /** * @param args the command line arguments * little test driver */ public static void main (String args[]) { Random generator = new Random(); Account all[] = new Account[10]; // define array of 10 accounts // actually create the accounts // Significant Java difference - the array itself is just a reference really for (int cnt = 0; cnt < 10; cnt++) { // assign a pin randomly - generated random integer and convert to string int rand = generator.nextInt(10000); String newPin = Integer.toString(rand); all[cnt] = new Account(newPin,0); } boolean ok; double newBal = 0; ok = all[0].deposit(50); if (! ok) { System.out.println(" My bad #1"); } ok = all[1].deposit(-30); if (! ok) { System.out.println(" My bad #2"); } // display the accounts System.out.println("All accounts: "); for (int cnt = 0; cnt < all.length; cnt++) { System.out.println(all[cnt].toString()); } ///////// Don't do the below (or at least don't show how it works) until we cover interfaces // try sorting array //Sorts.insertSort(all); // my sort Arrays.sort(all); // library sort // display the accounts System.out.println("Sorted accounts: "); for (int cnt = 0; cnt < all.length; cnt++) { System.out.println(all[cnt].toString()); } // just to see Integer array sorted - just like Account array Integer vals [ ] = { new Integer(9), new Integer(3), new Integer(5), new Integer(1), new Integer(6), new Integer(2), new Integer(0), new Integer(8), new Integer(4), new Integer(7) }; System.out.println("Unsorted Integers"); for (int cnt = 0; cnt < vals.length; cnt++) { System.out.println(vals[cnt]); } //Sorts.insertSort(vals);// my sort Arrays.sort(vals); // library sort System.out.println("Sorted Integers"); for (int cnt = 0; cnt < vals.length; cnt++) { System.out.println(vals[cnt]); } // just to see int array sorted - just like Account array int ints [ ] = { 9, 3, 5, 1, 6, 2, 0, 8, 4, 7 }; System.out.println("Unsorted ints"); for (int cnt = 0; cnt < ints.length; cnt++) { System.out.println(ints[cnt]); } //Sorts.insertSort(ints);// my sort - invalid - not Comparable Arrays.sort(ints); // library sort - valid - declares versions for primitive arrays too System.out.println("Sorted ints"); for (int cnt = 0; cnt < ints.length; cnt++) { System.out.println(ints[cnt]); } Account cantClone = new Account("1234",100.00); System.out.println("cantClone: " + cantClone); Account cloned = new Account(); try { cloned = (Account) cantClone.clone(); //** not allowed - Account doesn't implement Cloneable // works if you change Account to implement Cloneable - done 9/18/02 System.out.println("cloned: " + cloned); } catch (CloneNotSupportedException ex) { System.out.println("Cant do this to an Account"); } if (cantClone.acctNum == cloned.acctNum) { // same memory for account num - shallow clone System.out.println("shallow clone"); // goes here if Account doean't override Object's clone() } else if (cantClone.acctNum.equals(cloned.acctNum)) { System.out.println("successful deep clone"); // goes here with version of clone currently commented out in Account } else { System.out.println("cantClone acct num: " + cantClone.acctNum); System.out.println("cloned acct num: " + cloned.acctNum); } // note change to one object's data fields that are objects doesn't impact other if deep clone // but impacts other if shallow clone cantClone.setAcctNum("3030"); cantClone.setPIN("99999"); System.out.println("cantClone: " + cantClone); System.out.println("cloned: " + cloned); //int finalAnswer = RedmondMsgIn.readValidInt("Please enter your age",0,120); //System.out.println("Your age is: " + finalAnswer); //int temperature = RedmondMsgIn.readValidInt("Please enter the current temperature in degrees fahrenheit",-5,110); //System.out.println("The current tempaerature is: " + temperature); System.exit(0); } }