Computer Science at AHS

Bank Project

Bank Project by Dr. Bezaire and Ms. DiBenedetto

The Bank Project is part of the summer work for AP Java 2024 - 2025. Using the UML diagram and project description, write the BankAccount, Bank, and BankClient classes and then turn them in by August 27, 2024. After writing and testing the classes, submit them to the CS50 autograder and look at the feedback. You can revise and resubmit your code multiple times. Make sure to look at the autograder's feedback each time to ensure that your code is correct and well-styled.

Also spend time thinking about why the classes are designed the way they are. After you have finished the project, look through the list of Questions. You do not need to turn them in, but you will be asked similar questions on a quiz within the first few class sessions.

Academic Honesty

It's important that you write this code yourself to help prepare for AP Java. Here's what's ok and not ok for this assignment:


The Summer Bank Project is an individual assignment
Yes Read through this site for assistance or refer to the Java online textbook
Yes Copy individual method headers from this site into your code
Yes Look at your own code from class last year
Yes Use standard debugging strategies
Yes Ask Dr. Bezaire or your classmates for verbal or email conceptual help or specific debugging help
Yes AI: Ask questions to and copy code snippets from the CS50 Duck Debugger Duck Debugger icon in CS50
Yes Ask questions or look at content on our private Stack Overflow for Teams site
Maybe Search and look at content on Stack Overflow. Do not copy code directly and make sure to cite any code in your program inspired by what you found on Stack Overflow. A simple comment with the link to the Stack Overflow page is sufficient
Maybe Show the erroneous part of your code to someone who has already successfully completed it for help with debugging. The person helping should not change your code or give their correction verbatim, but can point out where or what seems wrong in your code.
NoDo not look at or copy from someone else's code for this assigment
NoAI: Do not use any AI helpers other than the CS50 Duck Debugger built into your CS50 IDEDuck Debugger icon in CS50


You are responsible for fully understanding any code you submit in this class.

Reading Guide

This document contains many sections; refer to the reading guide below for suggestions based on your comfort level with Java, the CS50 IDE, and object oriented programming.

If you are ...
Less Comfortable More Comfortable Very Comfortable
Read ...
  1. Reference (as needed)
  2. UML
  3. Expectations
  4. Command Reference
  5. Demo
  6. Development Strategy,
    expanded ▶
  7. Checks
  8. Questions
  1. UML
  2. Expectations
  3. Command Reference
  4. Demo
  5. Development Strategy
  6. Checks
  7. Questions
  1. UML
  2. Expectations
  3. Command Reference
  4. Demo
  5. Challenges
  6. Questions

UML

This UML diagram was produced using https://yuml.me/. For a refresher on UML, see this UML reference. Pay attention to the method headers, including method and parameter names - these are clues to what the methods should be doing.
UML diagram showing relationship between the Bank, BankAccount, and BankClient classes

Expectations

In addition to having correct, well-styled code, it is also important to follow good design practices. Your code should:

  • Have appropriate and descriptive variable and method names; comment when needed
  • Not be repetitive (generalize repetitive chunks and delegate them to a callable method where possible)
  • Make good use of loops and logic to improve efficiency
  • Be properly encapsulated
  • Be well organized - BankAccount should handle all logic within the domain of BankAccount and nothing specific to Bank; Bank handles all Bank-related logic; and BankClient handles the user menu and manages the output from Bank, as well as managing all print statements to the user and inputs from the user
  • Have a header comment that includes your name as the author, the date you started working on the code, and the purpose of the overall project and each file

Command Reference

You will need to run these commands in the terminal of your CS50 IDE (Integrated Development Environment). For help understanding how to use the IDE, click here.

  1. Run this command to get the code template:
    wget https://www.andovercs.org/code/bank.zip; unzip bank.zip; cd bank;
  2. Next, run this command to open a file for editing:
    code BankAccount.java 
  3. To compile a file, run:
    javac BankAccount.java 
  4. To run a class with a main method, run:
    java BankAccount 
  5. After writing code, run this command to check your style score (1.00 is highest):
    style50 -o score BankAccount.java 
  6. For a visual of how to improve your style, run:
    style50 BankAccount.java 

    Or, while your file is active in the script editor, look to the right side of the tab strip for the style50 tab and click it. You will see a side-by-side view of your current file and the proposed changes to improve style. From here, you can click another tab to Accept changes which will make the proposed style changes for you.

  7. When you are ready to test or turn in your code, run this command to submit your code:
    submit50 mbezaire/checks/main/java/bank 

Demonstration

Your final working program should behave similarly to the following example.

Development Strategy

Download the starter code using the commands above. Work on the BankAccount class first. Once BankAccount works properly, then work on the logic of the Bank class without BankAccount objects. Next, incorporate BankAccount objects into the Bank class. Lastly, write BankClient, adding a menu in its main method. Once you have tested each menu option, put it into a loop so that your user can perform multiple transactions before quitting the program.

Test your code often and submit it to the autograder whenever you need feedback and again when you are done. Click these triangles to expand more detailed instructions:

Each class file should have a header comment describing its purpose, listing the date the code was written, and including the author name(s). For code developed from templates, the template author should also be listed. Choose descriptive names for your variables and methods, use proper indentation, camelCase, and correct capitalization rules. You can check your style with these commands. Add brief comment to any code that is not self-documenting (meaning the variable and method names sufficiently explain what is happening).

BankAccount
  1. First, add the fields listed in in the UML of Bank Account. Then, develop the methods of BankAccount with a hard-coded pin number (set to 1234) and assume users will only ever call the methods with arguments that make sense Create a BankAccount class with the following attributes:
    • String name
    • int pinNumber (4 digits) //unique
    • double balance
    Add the following methods to the BankAccount class:
    • a no-args constructor that sets default values for attributes
    • A constructor that accepts name and balance as parameters, randomly sets pinNumber
    • A constructor that accepts name as a parameter, sets balance to 0.0 and randomly sets pinNumber
    • A method with the header: void deposit(double amt) that accepts a double as a parameter and increases balance by this amount. It should not accept negative amt values.
    • A method with the header: double withdraw(double amt) that accepts a double as a parameter and decreases the balance by this amount as long as it does not cause the balance to become negative. It should return the amount that was withdrawn. (If balance is 500. And user tries to withdraw 600, only 500 will be removed from the account and the return value will be 500)
    • A getter method with the header double getBalance() that returns balance
    • A getter method with the header String getName() that returns the name
    • A getter method with the header int getPinNumber() that returns pinNumber
    • A method with the header boolean validateAccount(String n, int p) that returns true if n matches name and p matches pinNumber. Returns false otherwise.
    • A method with the header String toString() that returns name, pinNumber and balance. The balance does NOT need to be formatted exactly like money with 2 decimal places.
  2. After the methods work with reasonable arguments, next tackle unreasonable arguments: add logic so that users can't deposit negative amounts (so they can't sneakily use deposit to withdraw money) and also add logic to prevent users from withdrawing more than they have in their account and from withdrawing a negative amount of money. Test your logic to confirm it works. Test the BankAccount class by creating a BankAccountTester program or adding a main method to BankAccount. Create several BankAccount objects, use a Scanner or hard-code inputs so that you can test what happens when you try to withdraw a negative amount, withdraw more money than is in the account, deposit an negative amount, etc.
  3. Next, work on the validateAccount method. It's especially helpful to have a hard-coded pin value while testing this method. Test this feature before moving on. Both the name and the pin will need to be checked against what the user supplies. The name field is a String; recall that Strings must be checked for equality a different way than numbers (because they are objects). Make use of the equals method.
  4. Lastly, remove the hard-coded pin number and replace it with a call to a random pin generator that will ensure a 4-digit int, and then test your code.

    Since the pinNumber field is an integer, the only way to ensure that it has a 4-digit number is to make the numeric value between 1000 and 9999. Within this range, any number should be equally likely to be assigned as the pinNumber. That is 9000 unique numbers!

    You may use Math.random() or the Random class's nextInt() method for this. If you use the Random class, remember:

    • Import it using: import java.util.Random
    • Create a new Random object
    • When calling the nextInt() method of your Random object, recall that it takes one argument; the number of random states, and can then return any number from 0 to that total number of states (random numbers) - 1.

    Validate all of your methods and once you are confident they work, you can remove the main method from BankAccount if you added it. If you made a separate file, no need to remove anything as long as all the print statements and any Scanner calls are removed from BankAccount.java before you submit your work.

Once BankAccount seems to work, submit your code so far using:

submit50 mbezaire/checks/main/java/bank 

The checks related to Bank will not pass yet, and that's OK! You're just looking for the BankAccount checks to pass. Once they pass, you're ready to move onto Bank.

Bank
Create a Bank class that supports up to 3 BankAccounts. Do not use Arrays or any type of Collection or List. Each BankAccount will be stored in a separate field. Add all the fields and set them to hard-coded values to start. Write the Bank's constructor, which should accept name as a string and initialize the three BankAccount objects to null. Add a variable numAccounts that keeps track of number of accounts. The constructor should set numAccounts to 0 to start. A final static variable of MAX_ACCOUNTS should be set to 3 (this can happen where you declare MAX_ACCOUNTS or in the constructor).
  1. Add all the methods, but have them only return a hard-coded value to start. Any methods that must return an object, hard code them to return null instead. Your first goal is to have a Bank class that compiles, without adding any real logic.

    Include the following methods:

    • public int addAccount(String n, double b), which will check to see if there is room in the bank for this account. If there is room, an account will be created using this information. addAccount should return the pinNumber that is created for this account or 0 if no account was created.
    • public boolean deposit(String name, int pin, double amt) - method will determine whether an account with name and pin exists. If it exists, it will use the deposit method of the appropriate Bank Account to change amount and return true. If it doesn't exist, it will return false.
    • public double withdraw(String name, int pin, double amt) - method will determine whether an account with name and pin exists. If it exists, it will use the withdraw method of the appropriate BankAccount to change amount and return the amount withdrawn. If it doesn't exist it will return 0 or a sentinel value that is used in BankClient to display a message about the incorrect name/pin combination.
    • public String showAccount(String name, int pin) - method will determine whether an account with name and pin exists. If it exists, it will call the toString method of the appropriate Bank Account to return account information to the user. Return null if no account is found.
    • private BankAccount findAccount(String name, int pin) - method returns a reference to the BankAccount instance variable that matches the name and pin. If no match exists, method returns null. This is a private method and should only be called by the Bank Class to help the deposit, withdraw, and showAccount methods.
  2. After your class compiles, next tackle the logic to keep track of the number of accounts open at the Bank, still without using the BankAccount fields yet. You'll want to make use of your MAX_ACCOUNTS and numAccounts variables. The goal is to have the addAccount method use and change those variables appropriately.
    • When addAccount is called, first check that there is space at the bank - numAccounts must be less than the MAX_ACCOUNTS variable (the capacity of the Bank). If there's no space, the addAccount method needs to stop running (return). Since it is supposed to return an int for the pinNumber, we need a value to return instead. This value must still be an int, but a number that can signal to the calling method that a new account was not created. Let's use 0 to signify that no new account was created.
    • If a BankAccount will be added, the number of accounts at the Bank will increase, so numAccounts should be increased by one.
  3. Next, submit your code again to check that you're on the right track. All BankAccount and only a couple of Bank checks should pass at this point. Once they pass, you're ready to incorporate BankAccount objects into your Bank class.
  4. Now implement the fields for three BankAccount objects and work on the logic of your createAccount method. Then, make sure your code compiles before moving on. Now, in addAccount, find the point in the logic where you've determined there's space for another account. Instantiate (create) an account with the information passed into the addAccount method. At the end of the method, make sure to return the reference to the account you instantiated.
  5. Next, work on your viewAccount method. Make sure your code compiles before moving on.
  6. Now, check that your Bank code works regardless of how many BankAccounts have been created. Look through every place in Bank.java where you refer to a BankAccount object. What would happen if that reference were null (didn't point to an object yet)? Add logic to your code to check for null values and deal with them appropriately, so that you don't run into any runtime errors when executing your code.
  7. Now, make sure your code compiles and then test it.
    • Test that you can add 1 account and view it
    • Then add 2 more accounts and view any of them
    • Try to add a 4th account, confirm that you cannot
  8. Next, work on your deposit and withdraw methods at the Bank level. They must call the corresponding methods in BankAccount but their return type is different. Then test your code again.

    Notice that the deposit method in Bank has a boolean return type. Think about when it should return true and when it should return false.

    There are two main steps that occur in Bank's deposit method. If either of them fail in some way, it would make sense to return false. If they are both successful, it would make sense to return true. The two steps are:
    1. Finding the correct BankAccount, where the name and pin match what's provided
    2. Calling the corresponding method on that BankAccount object and having it run successfully
    Think of how you can find out that these steps were successful and return false if they are not.

    For Bank's withdraw method, the return type is double, which should usually be the actual amount of money that was withdrawn. What value should be returned if step 1 above doesn't work, meaning the pin or name was incorrect and a matching BankAccount from which to withdraw is not found?

  9. Once all your Bank methods seem to work correctly, remove any print statements and main methods from Bank and BankAccount that you were using to test your code and ensure your code still compiles afterward.

Once Bank seems to work, submit your code again:

submit50 mbezaire/checks/main/java/bank 
If all of the Bank-related checks pass, you are ready to move onto BankClient.

BankClient

Next, create a BankClient program as a sort of user interface for your Bank. You'll need to create a Bank object (hard-code the name of the Bank; don't ask the user for it) and then provide a menu of options to the user. Based on their response, you'll collect any additional information you need, call the appropriate method(s) in Bank, add logic to evaluate the output of any method calls on Bank and then print information back to the user as expected.

Make sure to import java.util.Scanner so you can create a Scanner to collect user input. Print out a menu prompt in the main method. The menu should have the following options, in the same order:

  1. Create an Account - If room in Bank, prompt for name and starting balance, create account, generate an output “Welcome” message, output the pin number to the user.
  2. Make a Deposit - Prompt for name and pin number. If valid allow deposit. Output deposit amount.
  3. Make a Withdrawal - Prompt for name and pin number. If valid allow withdrawal. Output the amount withdrawn.
  4. View Account - Prompt for name and pin number. If valid display account information by calling showAccount
  5. Quit
For each choice in your menu, write a corresponding method in BankClient that:
  • asks for any additional information
  • calls the appropriate method in Bank
  • manages any output from that method as needed

Add a loop to your main method and move the menu code inside it so that your user can conduct multiple transactions without having to quit and restart the program.

Hint: when using a Scanner object to get input from the user at the terminal, you have access to methods such as:

  • nextInt()
  • nextDouble()
  • nextLine() // for Strings

Also recall that, when you make a call to nextInt() or nextDouble(), the Scanner object leaves a newline character (\n) hanging around, ready to cause trouble the next time you call nextLine(). To fix this issue, every time you make a call to nextInt() or nextDouble(), make a call to nextLine() afterward, like so:

BeforeAfter
int x = ear.nextInt();
String name = ear.nextLine(); // this is skipped
int x = ear.nextInt();
ear.nextLine(); // this eats the new line
String name = ear.nextLine(); // this one will work
If you developed a Custom.java file in Java Programming last year (Spring 2023 semester), you may copy it into your Bank project folder and use the methods you developed to avoid having to make the extra call to nextLine().


Test your code running this program, and then submit your code again.

Once you pass all the checks, look through your code again to ensure you have good design, and then check your style to ensure you have at least 0.85 out of 1.00.

submit50 mbezaire/checks/main/java/bank 

Checks

Submit50 will check:
  1. You are passing in three files: Bank.java, BankAccount.java, BankClient.java
  2. Each file has a header comment listing author(s), date started, and explaining the purpose.
  3. When a BankAccount is constructed, any arguments are used to set fields, any remaining fields are set to default values. Also, pinNumber is randomly set to a number between 1000 and 9999
  4. Only positive amounts can be deposited and will add to the balance
  5. Only positive amounts can be withdrawn and will be removed from the balance; balance cannot go below 0 (but withdrawal amount can be decreased). Withdrawn amount will be returned by the method
  6. BankAccount has a descriptive, user-friendly toString that includes all the fields
  7. Bank can be created with a name and 3 accounts
  8. Accounts are kept track of correctly, without using arrays, and up to 3 can be created
  9. Accounts can be found and viewed if the correct information is provided (and not otherwise)
  10. Accounts can be deposited into and withdrawn from
  11. Bank has a descriptive, user-friendly toString that includes the name, max number of accounts, and current number of accounts
  12. The instance variables of the Bank class and the BankAccount class are private.
  13. There are no print statements in either the Bank class or the BankAccount class (it's fine to have them in while you are working and testing, but remove them before you submit the last time).
  14. The BankAccount objects are completely hidden from the BankClient, meaning only the Bank class has the ability to modify and access the BankAccounts that belong to the Bank.
  15. Program works with no run time exceptions. For example, all menu options in BankClient should work regardless of how many accounts the Bank has.
Style50 will check:
  1. All standard Java conventions described in the style guide are adhered to.
Not automatic, you should check:
  1. Class names, variable names, method names are appropriate including the use of meaningful names, and conventional capitalization.
  2. Review code looking for examples of redundancy that could be abstracted out into a common method.

Questions

Here are some questions to get you thinking about how we design Object Oriented code in Java. Please think through and answer each of these questions for yourself. You do not need to turn them in. Some questions to think about

Challenges

Challenges are optional. Only work on them if you have completed the required work above, submitted it, and received full credit from the autograder. You can add any or all of these features and then submit to a different location when done:
submit50 mbezaire/checks/main/java/bank-challenge 
  • Add features that a Bank employee could use that are invisible to a customer. For example, a menu like this may have an option that is not displayed which allows a Bank employee to log in and view all accounts, delete accounts, etc. Add this option. For example if user types '5456', the menu should display a login screen requiring username and password. This will allow the super user privileges.
  • Fix the current limitation of this program in which once it powers down, all account information is lost. You can accomplish this using only logic we have learned in Java Programming.
  • Allow an existing Bank customer to log in and then conduct repeated transactions without having to enter their name and pin each time. Then, give them the option to log out and have the program "forget" their name and pin without quitting. The menu prompt should appear again and require the next user to log in before depositing, withdrawing, or viewing an account.

Reference

CS50 IDE

We use the CS50 IDE (Integrated Development Environment) in our class to write our code. To access this environment, first sign up for Github with a non-school email, and then visit the website: https://cs50.dev. Click the green "Log In" button and your IDE should load shortly.

To submit work for class, you will also need to join an online classroom. The link for joining the classroom is available on Schoology.

Once the CS50 IDE loads, you will see 3 main parts of it:

  • Left side: file explorer Here you can see your files and folders
  • Top: script editor The script editor where you write your code
  • Bottom: terminal The terminal allows you to run Bash (linux) commands to compile and run your programs, manage your folders and files, check your code style and submit your work

If you have any trouble accessing or using the IDE, check out this CS50 troubleshooting guide (coming soon!).

UML

UML stands for Unified Modeling Language. It is a way to represent classes and their relationships in an object-oriented program. Each class has its own rectangle containing areas for the class name, its fields, and its methods. There may be arrows or other lines between classes representing relationships between them, like "Dog HAS A Collar" or "Dog IS A Mammal". Click here for more information about UML diagrams.

Online Textbook

When you need help or additional lesson content, you may wish to consult this online Java textbook:
https://runestone.academy/ns/books/published/csawesome/index.html
Once the school year starts, we will begin working with a different textbook called Java Methods.

Stack Overflow

Programmers invariably end up on Stack Overflow when googling questions about programming. For students, it can be helpful if used with caution. Try to first look up your own notes or talk with your classmates to answer your questions. You are also welcome to ask the CS50 Duck Debugger in your CS50 IDE. If you have an account on our private Stack Overflow for Teams site, you can search there or ask a question.

If you have tried the above resources but still want to look at Stack Overflow, make sure you cite (paste the Stack Overflow link as a comment in your code) any questions that helped you and that you don't copy code from there directly or use coding concepts and keywords that you do not understand.

First, make sure the question that you are viewing has a positive rating to the left side of it (higher is better). Make sure to read the comments under the question, especially if they have a high positive rating to the left of them. If the question seems to fit your question, scroll down to the answer section and look for:

  • The answer with a green check mark to the left (if any). This is the answer that was accepted by the questioner as best answering their question. However, the person who asked the question gets to decide which answer to accept, so the answer with the green check mark may not always be the objectively best answer to the question. Therefore, you also want to look for:
  • The answer with the highest rating to the left of it (or any answer that is more highly rated than the accepted answer). The highest-rated answers are usually the most efficient, most likely to use good programming practices, and most likely to be acceptable to professional programmers.
After reading through an answer, look through any highly rated comments below it as well. Then paste a link to that web page into your code as a comment so that you can find it again if you need it and to serve as a citation if you write code based on what you found on Stack Overflow.

Stack Overflow for Teams

Around June 20, if you have completed Dr. Bezaire's survey and provided your github (non-school email), you'll now receive an invitation to join our private Stack Overflow for Teams site. You can search its content or post a question in it. You will need to respond to the invitation within 7 days or it will expire. If you do not see the invitation or it is more than 7 days old, please email Dr. Bezaire to request a new one.