Skip to content

Commit c5dd081

Browse files
authored
feat: adds Lesson 13 content and assignment (code-differently#311)
* feat: adds initial lesson 13 content and bank object model. * chore: adds javadoc * tests: added check acceptance criteria * chore: indicates class under test * docs: add assignment details Signed-off-by: Anthony D. Mays <[email protected]> * docs: add additional requirements Signed-off-by: Anthony D. Mays <[email protected]> * docs: adds additional assignment details Signed-off-by: Anthony D. Mays <[email protected]> * docs: adds technical requirements Signed-off-by: Anthony D. Mays <[email protected]> * docs: updates project requirements Signed-off-by: Anthony D. Mays <[email protected]> --------- Signed-off-by: Anthony D. Mays <[email protected]>
1 parent 74868e5 commit c5dd081

21 files changed

+1183
-0
lines changed

lesson_13/README.md

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Lesson 13
2+
3+
## Homework
4+
5+
* Complete [Applying SOLID principles](#applying-solid-principles-bank-atm) exercise.
6+
7+
## Applying SOLID Principles (Bank ATM)
8+
9+
Your task for this assignment is add enhancements to an ATM simulator. The [BankAtm][bankatm-file] is at the center of the model, allowing us to add one or more `CheckingAccount` instances and make withdrawals or deposits via cash or check. You will need to implement at least two of the following functional enhancements to the `BankAtm` class WITHOUT adding a new method. Note that you can update existing methods, however.
10+
11+
### Functional Requirements
12+
13+
* We want to support a `SavingsAccount` that works just like the `CheckingAccount`, but doesn't allow you to write checks against the account.
14+
* We want the `BankAtm` class to support the concept of a `BusinessCheckingAccount`. A business account requires that at least one of the owning accounts is a business.
15+
* In addition to supporting checks and cash, we also want to support the concept of another monetary instrument called a `MoneyOrder`. Unlike a `Check`, a `MoneyOrder` withdraws funds from a source account immediately on creation for the purposes of this simulation..
16+
* For traceability, all of the transactions in the `BankAtm` class should logged. Create an `AuditLog` class that keeps a record of all debits and credits to any account and integrate it with the `BankAtm` class.
17+
* For the `depositFunds` method that accepts a cash amount, we'd like the ability to deposit funds in a variety of currencies. Add a parameter that accepts a currency type and a new object that encapsulates the currency converter logic for converting a cash amount to the account currency type.
18+
19+
### Technical Requirements
20+
21+
* You must integrate new features into the `BankAtm` without adding a new public method. Existing public methods may be modified without breaking existing functionality.
22+
* You must update the `BankAtm` tests and may modify or add other applicable tests.
23+
* Feel free to add the minimal number of classes, interfaces, or abstract classes needed to fulfill each requirement.
24+
* You must update existing javadocs and may add new documentation for new types and methods you introduce.
25+
26+
[bank-folder]: ./bank/
27+
[bankatm-file]: ./bank/bank_app/src/main/java/com/codedifferently/lesson13/bank/BankAtm.java

lesson_13/bank/.gitattributes

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#
2+
# https://help.github.com/articles/dealing-with-line-endings/
3+
#
4+
# Linux start script should use lf
5+
/gradlew text eol=lf
6+
7+
# These are Windows script files and should use crlf
8+
*.bat text eol=crlf
9+

lesson_13/bank/.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Ignore Gradle project-specific cache directory
2+
.gradle
3+
4+
# Ignore Gradle build output directory
5+
build
+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
plugins {
2+
// Apply the application plugin to add support for building a CLI application in Java.
3+
application
4+
eclipse
5+
id("com.diffplug.spotless") version "6.25.0"
6+
id("org.springframework.boot") version "3.2.2"
7+
id("com.adarshr.test-logger") version "4.0.0"
8+
}
9+
10+
apply(plugin = "io.spring.dependency-management")
11+
12+
repositories {
13+
// Use Maven Central for resolving dependencies.
14+
mavenCentral()
15+
}
16+
17+
dependencies {
18+
// Use JUnit Jupiter for testing.
19+
testImplementation("com.codedifferently.instructional:instructional-lib")
20+
testImplementation("org.junit.jupiter:junit-jupiter:5.9.1")
21+
testImplementation("org.springframework.boot:spring-boot-starter-test")
22+
testImplementation("org.assertj:assertj-core:3.25.1")
23+
testImplementation("at.favre.lib:bcrypt:0.10.2")
24+
25+
// This dependency is used by the application.
26+
implementation("com.codedifferently.instructional:instructional-lib")
27+
implementation("com.google.guava:guava:31.1-jre")
28+
implementation("com.google.code.gson:gson:2.10.1")
29+
implementation("org.projectlombok:lombok:1.18.30")
30+
implementation("org.springframework.boot:spring-boot-starter")
31+
}
32+
33+
application {
34+
// Define the main class for the application.
35+
mainClass.set("com.codedifferently.lesson13.Lesson13")
36+
}
37+
38+
tasks.named<Test>("test") {
39+
// Use JUnit Platform for unit tests.
40+
useJUnitPlatform()
41+
}
42+
43+
44+
configure<com.diffplug.gradle.spotless.SpotlessExtension> {
45+
46+
format("misc", {
47+
// define the files to apply `misc` to
48+
target("*.gradle", ".gitattributes", ".gitignore")
49+
50+
// define the steps to apply to those files
51+
trimTrailingWhitespace()
52+
indentWithTabs() // or spaces. Takes an integer argument if you don't like 4
53+
endWithNewline()
54+
})
55+
56+
java {
57+
// don't need to set target, it is inferred from java
58+
59+
// apply a specific flavor of google-java-format
60+
googleJavaFormat()
61+
// fix formatting of type annotations
62+
formatAnnotations()
63+
}
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.codedifferently.lesson13;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
import org.springframework.context.annotation.Configuration;
6+
7+
@Configuration
8+
@SpringBootApplication(scanBasePackages = "com.codedifferently")
9+
public class Lesson13 {
10+
11+
public static void main(String[] args) {
12+
var application = new SpringApplication(Lesson13.class);
13+
application.run(args);
14+
}
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package com.codedifferently.lesson13.bank;
2+
3+
import com.codedifferently.lesson13.bank.exceptions.AccountNotFoundException;
4+
import java.util.HashMap;
5+
import java.util.Map;
6+
import java.util.Set;
7+
import java.util.UUID;
8+
9+
/** Represents a bank ATM. */
10+
public class BankAtm {
11+
private final Map<UUID, Customer> customerById = new HashMap<>();
12+
private final Map<String, CheckingAccount> accountByNumber = new HashMap<>();
13+
14+
/**
15+
* Adds a checking account to the bank.
16+
*
17+
* @param account The account to add.
18+
*/
19+
public void addAccount(CheckingAccount account) {
20+
accountByNumber.put(account.getAccountNumber(), account);
21+
account
22+
.getOwners()
23+
.forEach(
24+
owner -> {
25+
customerById.put(owner.getId(), owner);
26+
});
27+
}
28+
29+
/**
30+
* Finds all accounts owned by a customer.
31+
*
32+
* @param customerId The ID of the customer.
33+
* @return The unique set of accounts owned by the customer.
34+
*/
35+
public Set<CheckingAccount> findAccountsByCustomerId(UUID customerId) {
36+
return customerById.containsKey(customerId)
37+
? customerById.get(customerId).getAccounts()
38+
: Set.of();
39+
}
40+
41+
/**
42+
* Deposits funds into an account.
43+
*
44+
* @param accountNumber The account number.
45+
* @param amount The amount to deposit.
46+
*/
47+
public void depositFunds(String accountNumber, double amount) {
48+
CheckingAccount account = getAccountOrThrow(accountNumber);
49+
account.deposit(amount);
50+
}
51+
52+
/**
53+
* Deposits funds into an account using a check.
54+
*
55+
* @param accountNumber The account number.
56+
* @param check The check to deposit.
57+
*/
58+
public void depositFunds(String accountNumber, Check check) {
59+
CheckingAccount account = getAccountOrThrow(accountNumber);
60+
check.depositFunds(account);
61+
}
62+
63+
/**
64+
* Withdraws funds from an account.
65+
*
66+
* @param accountNumber
67+
* @param amount
68+
*/
69+
public void withdrawFunds(String accountNumber, double amount) {
70+
CheckingAccount account = getAccountOrThrow(accountNumber);
71+
account.withdraw(amount);
72+
}
73+
74+
/**
75+
* Gets an account by its number or throws an exception if not found.
76+
*
77+
* @param accountNumber The account number.
78+
* @return The account.
79+
*/
80+
private CheckingAccount getAccountOrThrow(String accountNumber) {
81+
CheckingAccount account = accountByNumber.get(accountNumber);
82+
if (account == null || account.isClosed()) {
83+
throw new AccountNotFoundException("Account not found");
84+
}
85+
return account;
86+
}
87+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.codedifferently.lesson13.bank;
2+
3+
import com.codedifferently.lesson13.bank.exceptions.CheckVoidedException;
4+
5+
/** Represents a check. */
6+
public class Check {
7+
private final String checkNumber;
8+
private final double amount;
9+
private final CheckingAccount account;
10+
private boolean isVoided = false;
11+
12+
/**
13+
* Creates a new check.
14+
*
15+
* @param checkNumber The check number.
16+
* @param amount The amount of the check.
17+
* @param account The account the check is drawn on.
18+
*/
19+
public Check(String checkNumber, double amount, CheckingAccount account) {
20+
if (amount < 0) {
21+
throw new IllegalArgumentException("Check amount must be positive");
22+
}
23+
this.checkNumber = checkNumber;
24+
this.amount = amount;
25+
this.account = account;
26+
}
27+
28+
/**
29+
* Gets the voided status of the check.
30+
*
31+
* @return True if the check is voided, and false otherwise.
32+
*/
33+
public boolean getIsVoided() {
34+
return isVoided;
35+
}
36+
37+
/** Voids the check. */
38+
public void voidCheck() {
39+
isVoided = true;
40+
}
41+
42+
/**
43+
* Deposits the check into an account.
44+
*
45+
* @param toAccount The account to deposit the check into.
46+
*/
47+
public void depositFunds(CheckingAccount toAccount) {
48+
if (isVoided) {
49+
throw new CheckVoidedException("Check is voided");
50+
}
51+
account.withdraw(amount);
52+
toAccount.deposit(amount);
53+
voidCheck();
54+
}
55+
56+
@Override
57+
public int hashCode() {
58+
return checkNumber.hashCode();
59+
}
60+
61+
@Override
62+
public boolean equals(Object obj) {
63+
if (obj instanceof Check other) {
64+
return checkNumber.equals(other.checkNumber);
65+
}
66+
return false;
67+
}
68+
69+
@Override
70+
public String toString() {
71+
return "Check{"
72+
+ "checkNumber='"
73+
+ checkNumber
74+
+ '\''
75+
+ ", amount="
76+
+ amount
77+
+ ", account="
78+
+ account.getAccountNumber()
79+
+ '}';
80+
}
81+
}

0 commit comments

Comments
 (0)