diff --git a/놀이터(예제 코드 작성)/solid-design-pattern-sample/README.md b/놀이터(예제 코드 작성)/solid-design-pattern-sample/README.md new file mode 100644 index 0000000..faa5870 --- /dev/null +++ b/놀이터(예제 코드 작성)/solid-design-pattern-sample/README.md @@ -0,0 +1,24 @@ +# SOLID & Design Pattern Sample + +## SOLID + +- SOLID 원칙들은 소프트웨어 작업에서 프로그래머가 소스 코드가 읽기 쉽고 확장하기 쉽게 될 때까지 소프트웨어 소스 코드를 리팩터링하여 코드 냄새를 제거하기 위해 적용할 수 있는 지침이다. +- 각 항목별 before & after 를 비교하면서 어떤 차이가 있는지 생각해본다. +- before & after 에 새로운, 또는 동일한 규칙(비즈니스 로직, 유효성 검사 등)을 적용해야 한다고 가정하고 변경을 시도해본다. + +### SRP(Single Responsibility Principle) + +- 단일 책임 원칙 +- 한 클래스는 하나의 책임만 가져야 한다. 즉, 한 클래스가 변경되는 이유는 한 가지여야 한다. + +#### 구현 요구사항 + +- 예금주의 이름으로 계좌를 생성할 수 있다. +- 계좌에 입금할 수 있다. +- 계좌에서 출금할 수 있다. + +## 참고자료 + +- [SOLID (객체 지향 설계)](https://ko.wikipedia.org/wiki/SOLID_(%EA%B0%9D%EC%B2%B4_%EC%A7%80%ED%96%A5_%EC%84%A4%EA%B3%84)) + + diff --git a/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/CreateAccountController.kt b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/CreateAccountController.kt new file mode 100644 index 0000000..f20011e --- /dev/null +++ b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/CreateAccountController.kt @@ -0,0 +1,18 @@ +package com.banjjoknim.soliddesignpatternsample.solid.srp.after + +import com.banjjoknim.soliddesignpatternsample.solid.srp.common.Account +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RequestMapping("/accounts") +@RestController +class CreateAccountController( + private val createAccountService: CreateAccountService +) { + @PostMapping("") + fun createAccount(@RequestBody request: CreateAccountRequest): Account { + return createAccountService.createAccount(request) + } +} diff --git a/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/CreateAccountRequest.kt b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/CreateAccountRequest.kt new file mode 100644 index 0000000..1ba5648 --- /dev/null +++ b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/CreateAccountRequest.kt @@ -0,0 +1,5 @@ +package com.banjjoknim.soliddesignpatternsample.solid.srp.after + +data class CreateAccountRequest( + val holderName: String +) diff --git a/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/CreateAccountService.kt b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/CreateAccountService.kt new file mode 100644 index 0000000..3347817 --- /dev/null +++ b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/CreateAccountService.kt @@ -0,0 +1,14 @@ +package com.banjjoknim.soliddesignpatternsample.solid.srp.after + +import com.banjjoknim.soliddesignpatternsample.solid.srp.common.Account +import com.banjjoknim.soliddesignpatternsample.solid.srp.common.AccountRepository +import org.springframework.stereotype.Service + +@Service +class CreateAccountService( + private val accountRepository: AccountRepository +) { + fun createAccount(request: CreateAccountRequest): Account { + return accountRepository.createAccount(request.holderName) + } +} diff --git a/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/DepositAccountController.kt b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/DepositAccountController.kt new file mode 100644 index 0000000..d9ec50a --- /dev/null +++ b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/DepositAccountController.kt @@ -0,0 +1,18 @@ +package com.banjjoknim.soliddesignpatternsample.solid.srp.after + +import com.banjjoknim.soliddesignpatternsample.solid.srp.common.Account +import org.springframework.web.bind.annotation.PatchMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RequestMapping("/accounts") +@RestController +class DepositAccountController( + private val depositAccountService: DepositAccountService +) { + @PatchMapping("/deposit") + fun depositAccount(@RequestBody request: DepositAccountRequest): Account { + return depositAccountService.depositAccount(request) + } +} diff --git a/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/DepositAccountRequest.kt b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/DepositAccountRequest.kt new file mode 100644 index 0000000..cbe5060 --- /dev/null +++ b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/DepositAccountRequest.kt @@ -0,0 +1,6 @@ +package com.banjjoknim.soliddesignpatternsample.solid.srp.after + +data class DepositAccountRequest( + val accountId: Long, + val amount: Int +) diff --git a/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/DepositAccountService.kt b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/DepositAccountService.kt new file mode 100644 index 0000000..0516286 --- /dev/null +++ b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/DepositAccountService.kt @@ -0,0 +1,16 @@ +package com.banjjoknim.soliddesignpatternsample.solid.srp.after + +import com.banjjoknim.soliddesignpatternsample.solid.srp.common.Account +import com.banjjoknim.soliddesignpatternsample.solid.srp.common.AccountRepository +import org.springframework.stereotype.Service + +@Service +class DepositAccountService( + private val accountRepository: AccountRepository +) { + fun depositAccount(request: DepositAccountRequest): Account { + val account = accountRepository.findAccount(request.accountId) + account.deposit(request.amount) + return account + } +} diff --git a/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/WithdrawalAccountController.kt b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/WithdrawalAccountController.kt new file mode 100644 index 0000000..f65b2d5 --- /dev/null +++ b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/WithdrawalAccountController.kt @@ -0,0 +1,18 @@ +package com.banjjoknim.soliddesignpatternsample.solid.srp.after + +import com.banjjoknim.soliddesignpatternsample.solid.srp.common.Account +import org.springframework.web.bind.annotation.PatchMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RequestMapping("/accounts") +@RestController +class WithdrawalAccountController( + private val withdrawalAccountService: WithdrawalAccountService +) { + @PatchMapping("/withdrawal") + fun withdrawal(@RequestBody request: WithdrawalAccountRequest): Account { + return withdrawalAccountService.withdrawalAccount(request) + } +} diff --git a/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/WithdrawalAccountRequest.kt b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/WithdrawalAccountRequest.kt new file mode 100644 index 0000000..d4aa847 --- /dev/null +++ b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/WithdrawalAccountRequest.kt @@ -0,0 +1,6 @@ +package com.banjjoknim.soliddesignpatternsample.solid.srp.after + +data class WithdrawalAccountRequest( + val accountId: Long, + val amount: Int +) diff --git a/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/WithdrawalAccountService.kt b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/WithdrawalAccountService.kt new file mode 100644 index 0000000..09f106e --- /dev/null +++ b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/after/WithdrawalAccountService.kt @@ -0,0 +1,16 @@ +package com.banjjoknim.soliddesignpatternsample.solid.srp.after + +import com.banjjoknim.soliddesignpatternsample.solid.srp.common.Account +import com.banjjoknim.soliddesignpatternsample.solid.srp.common.AccountRepository +import org.springframework.stereotype.Service + +@Service +class WithdrawalAccountService( + private val accountRepository: AccountRepository +) { + fun withdrawalAccount(request: WithdrawalAccountRequest): Account { + val account = accountRepository.findAccount(request.accountId) + account.withdrawal(request.amount) + return account + } +} diff --git a/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/before/AccountControllerBefore.kt b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/before/AccountControllerBefore.kt new file mode 100644 index 0000000..563d6db --- /dev/null +++ b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/before/AccountControllerBefore.kt @@ -0,0 +1,18 @@ +package com.banjjoknim.soliddesignpatternsample.solid.srp.before + +import com.banjjoknim.soliddesignpatternsample.solid.srp.common.Account +import org.springframework.web.bind.annotation.PatchMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RequestMapping("/accounts") +@RestController +class AccountControllerBefore( + private val accountServiceBefore: AccountServiceBefore +) { + @PatchMapping("/manage-account-before") + fun manageAccount(@RequestBody request: ManageAccountRequest): Account { + return accountServiceBefore.manageAccount(request) + } +} diff --git a/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/before/AccountServiceBefore.kt b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/before/AccountServiceBefore.kt new file mode 100644 index 0000000..a314e83 --- /dev/null +++ b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/before/AccountServiceBefore.kt @@ -0,0 +1,28 @@ +package com.banjjoknim.soliddesignpatternsample.solid.srp.before + +import com.banjjoknim.soliddesignpatternsample.solid.srp.common.Account +import com.banjjoknim.soliddesignpatternsample.solid.srp.common.AccountRepository +import org.springframework.stereotype.Service + +@Service +class AccountServiceBefore( + private val accountRepository: AccountRepository +) { + fun manageAccount(request: ManageAccountRequest): Account { + return when (request.type) { + ManageAccountType.CREATE -> { + accountRepository.createAccount(request.holderName) + } + ManageAccountType.DEPOSIT -> { + val account = accountRepository.findAccount(request.accountId) + account.deposit(request.amount) + account + } + ManageAccountType.WITHDRAWAL -> { + val account = accountRepository.findAccount(request.accountId) + account.withdrawal(request.amount) + account + } + } + } +} diff --git a/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/before/ManageAccountRequest.kt b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/before/ManageAccountRequest.kt new file mode 100644 index 0000000..1df3022 --- /dev/null +++ b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/before/ManageAccountRequest.kt @@ -0,0 +1,8 @@ +package com.banjjoknim.soliddesignpatternsample.solid.srp.before + +data class ManageAccountRequest( + val accountId: Long, + val holderName: String, + val amount: Int, + val type: ManageAccountType +) diff --git a/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/before/ManageAccountType.kt b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/before/ManageAccountType.kt new file mode 100644 index 0000000..f96e605 --- /dev/null +++ b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/before/ManageAccountType.kt @@ -0,0 +1,7 @@ +package com.banjjoknim.soliddesignpatternsample.solid.srp.before + +enum class ManageAccountType { + CREATE, // 생성 + DEPOSIT, // 입금 + WITHDRAWAL // 출금 +} diff --git a/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/common/Account.kt b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/common/Account.kt new file mode 100644 index 0000000..d650ecd --- /dev/null +++ b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/common/Account.kt @@ -0,0 +1,20 @@ +package com.banjjoknim.soliddesignpatternsample.solid.srp.common + +import javax.persistence.Entity +import javax.persistence.Id + +@Entity +class Account( + val holderName: String = "", + var balance: Int = 0, + @Id + val id: Long = 0, +) { + fun deposit(amount: Int) { + this.balance = this.balance + amount + } + + fun withdrawal(amount: Int) { + this.balance = this.balance - amount + } +} diff --git a/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/common/AccountRepository.kt b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/common/AccountRepository.kt new file mode 100644 index 0000000..aa0e27e --- /dev/null +++ b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/common/AccountRepository.kt @@ -0,0 +1,7 @@ +package com.banjjoknim.soliddesignpatternsample.solid.srp.common + +interface AccountRepository { + fun createAccount(holderName: String): Account + + fun findAccount(accountId: Long): Account +} diff --git a/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/common/AccountRepositoryStub.kt b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/common/AccountRepositoryStub.kt new file mode 100644 index 0000000..54dfdb2 --- /dev/null +++ b/놀이터(예제 코드 작성)/solid-design-pattern-sample/src/main/kotlin/com/banjjoknim/soliddesignpatternsample/solid/srp/common/AccountRepositoryStub.kt @@ -0,0 +1,14 @@ +package com.banjjoknim.soliddesignpatternsample.solid.srp.common + +import org.springframework.stereotype.Repository + +@Repository +class AccountRepositoryStub : AccountRepository { + override fun createAccount(holderName: String): Account { + return Account(holderName = "banjjoknim", balance = 0) + } + + override fun findAccount(accountId: Long): Account { + return Account(id = 1L, balance = 10000) + } +}