Skip to content

Commit 3e7bc3a

Browse files
authored
feat: adds lesson 17 homework and lesson 21 pre-work (#504)
Signed-off-by: Anthony D. Mays <[email protected]>
1 parent 0191faa commit 3e7bc3a

24 files changed

+1284
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Check Lesson 17 Java Pull Request
2+
3+
on:
4+
pull_request:
5+
branches: [ "main" ]
6+
paths:
7+
- "lesson_17/bank/**"
8+
9+
jobs:
10+
build:
11+
12+
runs-on: ubuntu-latest
13+
permissions:
14+
contents: read
15+
pull-requests: write
16+
17+
steps:
18+
- uses: actions/checkout@v4
19+
20+
- name: Set up JDK
21+
uses: actions/setup-java@v4
22+
with:
23+
java-version: '21'
24+
distribution: 'temurin'
25+
26+
- name: Build Lesson 17 with Java
27+
working-directory: ./lesson_17/bank
28+
run: ./gradlew check

.github/workflows/check_push.yml

+23
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ on:
1919
- "lesson_12/structs_ts/**"
2020
- "lesson_13/maps_java/**"
2121
- "lesson_13/maps_ts/**"
22+
- "lesson_14/exceptions/**"
23+
- "lesson_15/tdd/**"
24+
- "lesson_16/objects/**"
25+
- "lesson_17/bank/**"
2226
jobs:
2327
build:
2428
runs-on: ubuntu-latest
@@ -141,3 +145,22 @@ jobs:
141145
run: |
142146
npm ci
143147
npm run compile
148+
149+
- name: Build Lesson 14 with Java
150+
working-directory: ./lesson_14/exceptions
151+
run: ./gradlew assemble
152+
153+
- name: Build Lesson 15 with Java
154+
working-directory: ./lesson_15/tdd
155+
run: |
156+
./gradlew assemble
157+
./gradlew spotlessCheck
158+
159+
- name: Build Lesson 16 with Java
160+
working-directory: ./lesson_16/objects
161+
run: ./gradlew check
162+
163+
- name: Build Lesson 17 with Java
164+
working-directory: ./lesson_17/bank
165+
run: ./gradlew check
166+

lesson_17/README.md

+24-1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,27 @@ Please review the following resources before lecture:
1616

1717
## Homework
1818

19-
- TODO(anthonydmays): Make 'em work!!!
19+
- [ ] Complete [Applying SOLID principles](#applying-solid-principles-bank-atm) exercise.
20+
- [ ] Review [OOP Project](/project_oop/) documentation and complete user stories.
21+
22+
## Applying SOLID Principles (Bank ATM)
23+
24+
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.
25+
26+
### Functional Requirements
27+
28+
* We want to support a `SavingsAccount` that works just like the `CheckingAccount`, but doesn't allow you to write checks against the account.
29+
* 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.
30+
* 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..
31+
* 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.
32+
* ~~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.~~
33+
34+
### Technical Requirements
35+
36+
* You must integrate new features into the `BankAtm` without adding a new public method. Existing public methods may be modified without breaking existing functionality.
37+
* You must update the `BankAtm` tests and may modify or add other applicable tests.
38+
* Feel free to add the minimal number of classes, interfaces, or abstract classes needed to fulfill each requirement.
39+
* You must update existing javadocs and may add new documentation for new types and methods you introduce.
40+
41+
[bank-folder]: ./bank/
42+
[bankatm-file]: ./bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/BankAtm.java

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

0 commit comments

Comments
 (0)