feat : SOLID - OCP 샘플 코드 구현

This commit is contained in:
banjjoknim
2022-11-08 17:29:59 +09:00
parent f9af46e64a
commit e9b76a0024
15 changed files with 215 additions and 0 deletions

View File

@@ -17,6 +17,17 @@
- 계좌에 입금할 수 있다.
- 계좌에서 출금할 수 있다.
### OCP(Open/Closed 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))

View File

@@ -0,0 +1,20 @@
package com.banjjoknim.soliddesignpatternsample.solid.ocp.after
import com.banjjoknim.soliddesignpatternsample.solid.ocp.common.Payment
import com.banjjoknim.soliddesignpatternsample.solid.ocp.common.PaymentRepository
import com.banjjoknim.soliddesignpatternsample.solid.ocp.common.PaymentType
import org.springframework.stereotype.Repository
@Repository
class CardPaymentService(
private val paymentRepository: PaymentRepository
): PaymentServiceAfter {
override fun pay(request: PaymentRequestAfter): Payment {
println("카드 결제로 ${request.amount}원을 차감합니다.")
return paymentRepository.createPayment(request.amount, request.paymentType)
}
override fun getPaymentType(): PaymentType {
return PaymentType.CARD
}
}

View File

@@ -0,0 +1,20 @@
package com.banjjoknim.soliddesignpatternsample.solid.ocp.after
import com.banjjoknim.soliddesignpatternsample.solid.ocp.common.Payment
import com.banjjoknim.soliddesignpatternsample.solid.ocp.common.PaymentRepository
import com.banjjoknim.soliddesignpatternsample.solid.ocp.common.PaymentType
import org.springframework.stereotype.Repository
@Repository
class CashPaymentService(
private val paymentRepository: PaymentRepository
): PaymentServiceAfter {
override fun pay(request: PaymentRequestAfter): Payment {
println("현금드 결제로 ${request.amount}원을 차감합니다.")
return paymentRepository.createPayment(request.amount, request.paymentType)
}
override fun getPaymentType(): PaymentType {
return PaymentType.CASH
}
}

View File

@@ -0,0 +1,20 @@
package com.banjjoknim.soliddesignpatternsample.solid.ocp.after
import com.banjjoknim.soliddesignpatternsample.solid.ocp.common.Payment
import com.banjjoknim.soliddesignpatternsample.solid.ocp.common.PaymentRepository
import com.banjjoknim.soliddesignpatternsample.solid.ocp.common.PaymentType
import org.springframework.stereotype.Repository
@Repository
class CouponPaymentService(
private val paymentRepository: PaymentRepository
): PaymentServiceAfter {
override fun pay(request: PaymentRequestAfter): Payment {
println("쿠폰 결제는 잔고 차감이 없습니다.")
return paymentRepository.createPayment(request.amount, request.paymentType)
}
override fun getPaymentType(): PaymentType {
return PaymentType.COUPON
}
}

View File

@@ -0,0 +1,18 @@
package com.banjjoknim.soliddesignpatternsample.solid.ocp.after
import com.banjjoknim.soliddesignpatternsample.solid.ocp.common.Payment
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
@RequestMapping("/payments")
@RestController
class PaymentController(
private val paymentServiceFactory: PaymentServiceFactory
) {
@PostMapping("with-ocp")
fun pay(request: PaymentRequestAfter): Payment {
val paymentService = paymentServiceFactory.getPaymentService(request.paymentType)
return paymentService.pay(request)
}
}

View File

@@ -0,0 +1,8 @@
package com.banjjoknim.soliddesignpatternsample.solid.ocp.after
import com.banjjoknim.soliddesignpatternsample.solid.ocp.common.PaymentType
data class PaymentRequestAfter(
val amount: Int,
val paymentType: PaymentType
)

View File

@@ -0,0 +1,10 @@
package com.banjjoknim.soliddesignpatternsample.solid.ocp.after
import com.banjjoknim.soliddesignpatternsample.solid.ocp.common.Payment
import com.banjjoknim.soliddesignpatternsample.solid.ocp.common.PaymentType
interface PaymentServiceAfter {
fun pay(request: PaymentRequestAfter): Payment
fun getPaymentType(): PaymentType
}

View File

@@ -0,0 +1,27 @@
package com.banjjoknim.soliddesignpatternsample.solid.ocp.after
import com.banjjoknim.soliddesignpatternsample.solid.ocp.common.PaymentType
import org.springframework.stereotype.Component
@Component
class PaymentServiceFactory(val paymentServices: List<PaymentServiceAfter>) {
fun getPaymentService(paymentType: PaymentType): PaymentServiceAfter {
return this.paymentServices.find { it.getPaymentType() == paymentType }
?: throw NoSuchElementException("해당 결제방식에 대한 구현이 존재하지 않습니다.")
}
}
//@Component
//class PaymentServiceFactory(
// private val cashPaymentService: CashPaymentService,
// private val cardPaymentService: CardPaymentService,
// private val couponPaymentService: CouponPaymentService
//) {
// fun findPaymentService(paymentType: PaymentType): PaymentServiceAfter {
// return when (paymentType) {
// PaymentType.CASH -> cashPaymentService
// PaymentType.CARD -> cardPaymentService
// PaymentType.COUPON -> couponPaymentService
// }
// }
//}

View File

@@ -0,0 +1,18 @@
package com.banjjoknim.soliddesignpatternsample.solid.ocp.before
import com.banjjoknim.soliddesignpatternsample.solid.ocp.common.Payment
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("/payments")
@RestController
class PaymentControllerBefore(
private val paymentServiceBefore: PaymentServiceBefore
) {
@PostMapping("/none-ocp")
fun pay(@RequestBody request: PaymentRequestBefore): Payment {
return paymentServiceBefore.pay(request)
}
}

View File

@@ -0,0 +1,8 @@
package com.banjjoknim.soliddesignpatternsample.solid.ocp.before
import com.banjjoknim.soliddesignpatternsample.solid.ocp.common.PaymentType
data class PaymentRequestBefore(
val amount: Int,
val type: PaymentType
)

View File

@@ -0,0 +1,21 @@
package com.banjjoknim.soliddesignpatternsample.solid.ocp.before
import com.banjjoknim.soliddesignpatternsample.solid.ocp.common.Payment
import com.banjjoknim.soliddesignpatternsample.solid.ocp.common.PaymentRepository
import com.banjjoknim.soliddesignpatternsample.solid.ocp.common.PaymentType
import org.springframework.stereotype.Service
@Service
class PaymentServiceBefore(
private val paymentRepository: PaymentRepository
) {
fun pay(request: PaymentRequestBefore): Payment {
when (request.type) {
PaymentType.CASH -> println("현금 결제로 ${request.amount}원을 차감합니다.")
PaymentType.CARD -> println("카드 결제로 ${request.amount}원을 차감합니다.")
PaymentType.COUPON -> println("쿠폰 결제는 잔고 차감이 없습니다.")
// NewPaymentType -> ...
}
return paymentRepository.createPayment(request.amount, request.type)
}
}

View File

@@ -0,0 +1,12 @@
package com.banjjoknim.soliddesignpatternsample.solid.ocp.common
import javax.persistence.Entity
import javax.persistence.Id
@Entity
class Payment(
val amount: Int,
val type: PaymentType,
@Id
val id: Long = 0L
)

View File

@@ -0,0 +1,5 @@
package com.banjjoknim.soliddesignpatternsample.solid.ocp.common
interface PaymentRepository {
fun createPayment(amount: Int, paymentType: PaymentType): Payment
}

View File

@@ -0,0 +1,10 @@
package com.banjjoknim.soliddesignpatternsample.solid.ocp.common
import org.springframework.stereotype.Repository
@Repository
class PaymentRepositoryStub : PaymentRepository {
override fun createPayment(amount: Int, paymentType: PaymentType): Payment {
return Payment(amount = amount, type = paymentType)
}
}

View File

@@ -0,0 +1,7 @@
package com.banjjoknim.soliddesignpatternsample.solid.ocp.common
enum class PaymentType {
CASH,
CARD,
COUPON
}