Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- akka 강좌
- 이더리움
- 주키퍼
- hyperledger fabric
- CORDA
- Adapter 패턴
- Golang
- 파이썬 강좌
- 스칼라 동시성
- 스칼라 강좌
- 플레이프레임워크
- play 강좌
- Play2
- play2 강좌
- 하이브리드앱
- Akka
- 파이썬 동시성
- 파이썬
- Play2 로 웹 개발
- 스칼라
- 그라파나
- 파이썬 데이터분석
- 안드로이드 웹뷰
- 파이썬 머신러닝
- 블록체인
- 엔터프라이즈 블록체인
- Actor
- 하이퍼레저 패브릭
- 스위프트
- Hyperledger fabric gossip protocol
Archives
- Today
- Total
HAMA 블로그
[코틀린 코딩 습작] Visitor 본문
상황은 다음과 같다.
어느 온라인서점에는 멤버별로 금,은,동의 등급이 있으며,
각 멤버에게 등급별로 베네핏을 주려고 하며, 베네핏의 종류는 A,B,C가 있다.
멤버는 각 베네핏을 모두 합친 만큼의 베네핏을 받을 수 있다.
원래 베네핏에 대한 로직은 더 복잡해 질 수 있지만, 예제에서는 10,20,30점으로 굉장히 단순화 하였다.
code1)
enum class GRADE {
BRONZE,
SILVER,
GOLD
}
class Member(val grade: GRADE) {
fun calcBenefit(): Int {
var total = 0
when(grade) {
GRADE.BRONZE -> {
// discount benefit
total += 10
// coupon benefit
total += 20
// point benefit
total += 30
}
GRADE.SILVER -> {
// discount benefit
total += 20
// coupon benefit
total += 30
// point benefit
total += 40
}
GRADE.GOLD -> {
// a benefit
total += 30
// b benefit
total += 40
// c benefit
total += 50
}
else -> {
throw IllegalArgumentException("unknown grade type!!")
}
}
return total
}
}
fun main() {
val memberA = Member(GRADE.BRONZE)
val benefitA = memberA.calcBenefit()
println("BRONZE Benefit: " + benefitA)
val memberB = Member(GRADE.GOLD)
val benefitB = memberB.calcBenefit()
println("GOLD Benefit: " + benefitB)
}
code2)
sealed class Member
class BronzeMember : Member()
class SilverMember : Member()
class GoldMember : Member()
class Benefit {
fun discount(member: Member): Int {
return when(member){
is BronzeMember -> 10
is SilverMember -> 20
is GoldMember -> 30
}
}
fun coupon(member: Member): Int {
return when(member){
is BronzeMember -> 20
is SilverMember -> 30
is GoldMember -> 40
}
}
fun point(member: Member): Int {
return when(member){
is BronzeMember -> 30
is SilverMember -> 40
is GoldMember -> 50
}
}
}
fun main() {
val benefit = Benefit()
val memberA = BronzeMember()
val totalBenefitA = benefit.discount(memberA) + benefit.coupon(memberA) + benefit.point(memberA)
println("BRONZE Benefit: " + totalBenefitA)
}
code3) visitor 패턴
보통 요소들을 iterator 돌면서 로직을 적용하는데, visitor는 그 반대로 생각하면 쉽다.
로직이 요소들을 방문하면서 액션이 이루어진다. 이 코드에서 요소는 멤버이고, 로직은 각 베네핏종류이다.
sealed class Member {
var totalBenefit : Int = 0
abstract fun calcBenefit(benefit: BenefitVisitor)
}
class BronzeMember : Member() {
override fun calcBenefit(benefit: BenefitVisitor) {
totalBenefit += benefit.calcBenefit(this)
}
}
class SilverMember : Member(){
override fun calcBenefit(benefit: BenefitVisitor) {
totalBenefit += benefit.calcBenefit(this)
}
}
class GoldMember : Member(){
override fun calcBenefit(benefit: BenefitVisitor){
totalBenefit += benefit.calcBenefit(this)
}
}
interface BenefitVisitor {
fun calcBenefit(member: BronzeMember): Int
fun calcBenefit(member: SilverMember): Int
fun calcBenefit(member: GoldMember): Int
}
class DiscountBenefit : BenefitVisitor {
override fun calcBenefit(member: BronzeMember): Int {
// bronzemember 특화로직일을 함
return 10
}
override fun calcBenefit(member: SilverMember): Int{
// silvermember 특화로직일을 함
return 20
}
override fun calcBenefit(member: GoldMember): Int {
// goldmember 특화로직일을 함
return 30
}
}
class CouponBenefit : BenefitVisitor {
override fun calcBenefit(member: BronzeMember): Int {
return 20
}
override fun calcBenefit(member: SilverMember): Int{
return 30
}
override fun calcBenefit(member: GoldMember): Int {
return 40
}
}
class PointBenefit : BenefitVisitor {
override fun calcBenefit(member: BronzeMember): Int {
return 30
}
override fun calcBenefit(member: SilverMember): Int{
return 40
}
override fun calcBenefit(member: GoldMember): Int {
return 50
}
}
fun main() {
val memberBronze = BronzeMember()
val memberSilver = SilverMember()
val memberGold = GoldMember()
val discount = DiscountBenefit()
val coupon = CouponBenefit()
val point = PointBenefit()
memberBronze.calcBenefit(discount)
memberBronze.calcBenefit(coupon)
memberBronze.calcBenefit(point)
memberSilver.calcBenefit(coupon)
memberGold.calcBenefit(point)
println("total : " + memberBronze.totalBenefit)
}
double dispaching이 일어나는것을 볼 수 있으며, if문은 없어졌지만, 먼가 장황스럽다고 느껴질수도 있다.
Visitor Pattern의 의도는 데이터 구조와 처리를 분리하는 패턴인데, 사실 visitor패턴은 Gof의 모든 패턴중에 가장 논쟁이 많아질 수 있는 패턴이라 보여진다. Benefit은 member에 대해 속속들이 알아야 할 수가 있으며, 원래 객체(자료구조의 반대개념)가 가진 단점인 타입 추가에는 유연하나, 기능추가엔 많은 변경을 요하는 문제점에다가 여기서는 요소추가가 많아질 경우 바꿔야 할 경우까지 많아 진다. 다만 요소는 고정될 가능성이 크고, 로직부분이 많아질 가능성이 큰 시스템에서 유용 할 수 있으니 트레이드오프를 잘 계산해서 사용하면 될 듯하다.
'Kotlin' 카테고리의 다른 글
[코틀린 코딩 습작] coroutine & channel (0) | 2021.06.07 |
---|---|
[코틀린 코딩 습작] Tuple (0) | 2021.06.07 |
[코틀린 코딩 습작] Intercepting Fillter (0) | 2021.05.15 |
[코틀린 코딩 습작] Annotation & Reflection (0) | 2021.05.15 |
[코틀린 코딩 습작] Future (0) | 2021.05.15 |
Comments