diff --git a/README.md b/README.md index 44b0ee7..dad5594 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Kotlin OOP and FP Design Patterns * [x] [Observer](#observer) * [x] [State](#state) * [ ] [Template](#template) - * [ ] [Visitor](#visitor) + * [x] [Visitor](#visitor) * [Creational Patterns](#creational) * [ ] [Abstract Factory](#abstract-factory) * [ ] [Builder](#builder) @@ -311,12 +311,64 @@ Template **In progress** -Visitor +[Visitor](/src/main/kotlin/oop/Visitor) ------ > Represent an operation to be performed on the elements of an object structure. It lets you define a new operation without changing the classes of the elements on which it operates. -**In progress** +### Example + +```kotlin +interface PaymentMethodVisitable { + fun accept(visitor: PaymentMethodVisitor) +} + +sealed class PaymentMethod(var moneyPayed: Float, var cost: Float) : PaymentMethodVisitable { + + class CashPaymentMethod(moneyPayed: Float, cost: Float) : PaymentMethod(moneyPayed, cost) { + override fun accept(visitor: PaymentMethodVisitor) = visitor.visit(this) + } + + class CreditCardPaymentMethod(cost: Float) : PaymentMethod(cost, cost) { + override fun accept(visitor: PaymentMethodVisitor) = visitor.visit(this) + } + +} + +interface PaymentMethodVisitor { + fun visit(paymentMethod: PaymentMethod.CashPaymentMethod) + fun visit(paymentMethod: PaymentMethod.CreditCardPaymentMethod) +} + +class CashRegister(initialAmount: Float) : PaymentMethodVisitor { + + var cash = initialAmount + private set + + override fun visit(paymentMethod: PaymentMethod.CashPaymentMethod) { + cash += paymentMethod.moneyPayed + cash -= (paymentMethod.moneyPayed - paymentMethod.cost) + paymentMethod.moneyPayed = (paymentMethod.moneyPayed - paymentMethod.cost) + } + + override fun visit(paymentMethod: PaymentMethod.CreditCardPaymentMethod) { + cash += paymentMethod.cost + paymentMethod.moneyPayed = 0 + } + +} +``` + +### Usage + +```kotlin +val cashRegister = CashRegister(0.0f) +val cash = PaymentMethod.CashPaymentMethod(15.50f, 12.50f) +cashRegister.visit(cash) + +println(cashRegister.cash) // 12.50f +println(cash.moneyPayed) // 3f +``` Creational ========== diff --git a/src/main/kotlin/oop/Visitor/PaymentMethodVisitable.kt b/src/main/kotlin/oop/Visitor/PaymentMethodVisitable.kt new file mode 100644 index 0000000..d8da8da --- /dev/null +++ b/src/main/kotlin/oop/Visitor/PaymentMethodVisitable.kt @@ -0,0 +1,19 @@ +package oop.Visitor + + +interface PaymentMethodVisitable { + fun accept(visitor: PaymentMethodVisitor) +} + +sealed class PaymentMethod(var moneyPayed: Int, var cost: Int) : PaymentMethodVisitable { + + class CashPaymentMethod(moneyPayed: Float, cost: Float) : + PaymentMethod((moneyPayed * 100).toInt(), (cost * 100).toInt()) { + override fun accept(visitor: PaymentMethodVisitor) = visitor.visit(this) + } + + class CreditCardPaymentMethod(cost: Float) : PaymentMethod((cost * 100).toInt(), (cost * 100).toInt()) { + override fun accept(visitor: PaymentMethodVisitor) = visitor.visit(this) + } + +} diff --git a/src/main/kotlin/oop/Visitor/PaymentMethodVisitor.kt b/src/main/kotlin/oop/Visitor/PaymentMethodVisitor.kt new file mode 100644 index 0000000..71294fd --- /dev/null +++ b/src/main/kotlin/oop/Visitor/PaymentMethodVisitor.kt @@ -0,0 +1,25 @@ +package oop.Visitor + + +interface PaymentMethodVisitor { + fun visit(paymentMethod: PaymentMethod.CashPaymentMethod) + fun visit(paymentMethod: PaymentMethod.CreditCardPaymentMethod) +} + +class CashRegister(initialAmount: Float) : PaymentMethodVisitor { + + var cash = (initialAmount * 100).toInt() + private set + + override fun visit(paymentMethod: PaymentMethod.CashPaymentMethod) { + cash += paymentMethod.moneyPayed + cash -= (paymentMethod.moneyPayed - paymentMethod.cost) + paymentMethod.moneyPayed = (paymentMethod.moneyPayed - paymentMethod.cost) + } + + override fun visit(paymentMethod: PaymentMethod.CreditCardPaymentMethod) { + cash += paymentMethod.cost + paymentMethod.moneyPayed = 0 + } + +} diff --git a/src/test/kotlin/oop/Visitor/VisitorTest.kt b/src/test/kotlin/oop/Visitor/VisitorTest.kt new file mode 100644 index 0000000..61e5185 --- /dev/null +++ b/src/test/kotlin/oop/Visitor/VisitorTest.kt @@ -0,0 +1,53 @@ +package oop.Visitor + +import com.natpryce.hamkrest.Matcher +import com.natpryce.hamkrest.assertion.assert +import org.junit.Test + +class VisitorTest { + + val `is` = { amount: Number -> Matcher(Number::equals, amount) } + fun Int.toMoney() = this.div(100f) + + @Test + fun `cash should increment exact amount when payment is credit card`() { + val cashRegister = CashRegister(0f) + val creditCard = PaymentMethod.CreditCardPaymentMethod(15.50f) + + cashRegister.visit(creditCard) + + assert.that(cashRegister.cash.toMoney(), `is`(15.50f)) + } + + @Test + fun `moneyPayed should be 0 when payment is credit card after payment`() { + val cashRegister = CashRegister(0.0f) + val creditCard = PaymentMethod.CreditCardPaymentMethod(15.50f) + + cashRegister.visit(creditCard) + + assert.that(creditCard.moneyPayed.toMoney(), `is`(0.0f)) + } + + @Test + fun `cash should increment payedAmount and decrease exchange amount when payment is cash`() { + val cashRegister = CashRegister(0.0f) + val cash = PaymentMethod.CashPaymentMethod(20.0f, 19.99f) + + cashRegister.visit(cash) + + assert.that(cashRegister.cash.toMoney(), `is`(19.99f)) + } + + @Test + fun `moneyPayed should be equal to exchange when payment is cash`() { + val cashRegister = CashRegister(0.0f) + val cash = PaymentMethod.CashPaymentMethod(20.0f, 19.99f) + + cashRegister.visit(cash) + + assert.that(cash.moneyPayed.toMoney(), `is`(0.01f)) + } + + +}