Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Visitor pattern #39

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 55 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
==========
Expand Down
19 changes: 19 additions & 0 deletions src/main/kotlin/oop/Visitor/PaymentMethodVisitable.kt
Original file line number Diff line number Diff line change
@@ -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)
}

}
25 changes: 25 additions & 0 deletions src/main/kotlin/oop/Visitor/PaymentMethodVisitor.kt
Original file line number Diff line number Diff line change
@@ -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
}

}
53 changes: 53 additions & 0 deletions src/test/kotlin/oop/Visitor/VisitorTest.kt
Original file line number Diff line number Diff line change
@@ -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))
}


}