Skip to content
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
23 changes: 12 additions & 11 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ group 'com.cloudcoders'
version '1.0-SNAPSHOT'

buildscript {
ext.kotlin_version = '1.1.1'
ext.kotlin_version = '1.1.1'

repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

apply plugin: 'java'
Expand All @@ -18,11 +18,12 @@ apply plugin: 'kotlin'
sourceCompatibility = 1.5

repositories {
mavenCentral()
mavenCentral()
}

dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
testCompile group: 'junit', name: 'junit', version: '4.11'
testCompile "com.natpryce:hamkrest:1.4.0.0"
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
testCompile group: 'junit', name: 'junit', version: '4.11'
testCompile "com.natpryce:hamkrest:1.4.0.0"
testCompile 'io.kotlintest:kotlintest:2.0.2'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package oop.Observer.subscription

class PublishSubject<A>(private val observers: MutableList<Observer<A>> = mutableListOf()) {

fun register(observer: Observer<A>): Observer<A> {
observers.add(observer)
return observer
}

fun notify(value: A) {
observers.forEach { it.update(value) }
}

}

open class Observer<A>(private val value: A) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why open class? You could have made it abstract or even an interface with implementation (I think Kotlin let to do that...)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, should exist a Observer interface, but for this example is more clear without a one component more.


private var subscription: Subscription<A>? = null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need a Subscription class? 🤔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to subscribe and unsuscribe

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But the register method is in the publisher, you only need to add another method to remove subscriber


open fun update(value: A) {
if (subscription?.isSubscribed ?: false) {
subscription?.update?.invoke(value)
}
}

fun subscribe(success: (A) -> Unit, update: (A) -> Unit): Subscription<A> {
success(value)
return Subscription(update).also { subscription = it }
}

}


class Subscription<A> internal constructor(internal val update: (A) -> Unit,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Internal constructor??? what is that? 😲

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

internal is like in java a class without public, is a visibility package only.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is for testing purpose I suppose?

internal var isSubscribed: Boolean = true) {

fun unregister() {
isSubscribed = false
}

fun register() {
isSubscribed = true
}
}

fun main(args: Array<String>) {
val success: (String) -> Unit = { println("Value: $it") }

val subject: PublishSubject<String> = PublishSubject()

var firstSub = subject.register(Observer("First request a value and updates"))
.subscribe(success, { println("First updated: $it") })
var secondSub = subject.register(Observer("Second request only updates"))
.subscribe({}, { println("Second updated: $it") })
var thirdSub = subject.register(Observer("Third request a value"))
.subscribe(success, {})

println()
println("Notify: Toni")
subject.notify("Toni"); println()
println("Notify: Cotel")
subject.notify("Cotel"); println()

println("Unregister all"); println()
firstSub.unregister()
secondSub.unregister()
thirdSub.unregister()

println("Notify: Fran")
subject.notify("Fran")
println("Nothing happens");println()

println("Register first and second"); println()
firstSub.register()
secondSub.register()

println("Notify: That's all")
subject.notify("That's all"); println()
}
66 changes: 65 additions & 1 deletion src/main/kotlin/oop/Proxy/ProtectionProxy.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,77 @@
package oop.Proxy

interface Car {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a missed commit or it is included too?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a gost commit lol hahaha

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ghost* 👻

fun isNovel(): Boolean
fun drive()
}

class CarProtectionProxy(private val realObject: Car) : Car {
override fun drive() {
if (!realObject.isNovel()) {
realObject.drive()
} else {
println("You can't drive a car")
}
}

override fun isNovel(): Boolean = realObject.isNovel()
}

class CarVirtualProxy(private val create: () -> Car) : Car {

private val realObject by lazy {
create()
}

override fun drive() = realObject.drive()

override fun isNovel(): Boolean = realObject.isNovel()
}

class CarSmartProxy(private val realObject: Car,
var accesDriver: Int = 0) : Car {

override fun drive() {
realObject.drive()
accesDriver++
}

override fun isNovel(): Boolean = realObject.isNovel()
}

class RealCar(val name: String, val driverAge: Int) : Car {
override fun drive() = println("$name is driving a car")

override fun isNovel(): Boolean = driverAge < 18
}

fun main(args: Array<String>) {


var carVirtualProxy = CarVirtualProxy({ RealCar("tonilopezmr", 5) })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you wrap that constructor parameter in a lambda?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I confused it with CarProtectionProxy which has not function as a constructor parameter. My bad 😝

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because Virtual is lazy

var carProtectionProxy = CarProtectionProxy(carVirtualProxy)
var carSmartProxy = CarSmartProxy(carVirtualProxy)

//Subject or Client usa el proxy

carProtectionProxy.drive()
carSmartProxy.drive()

println("Toni has driven ${carSmartProxy.accesDriver} times")




}

interface Payment {
fun pay(transaction: Transaction)
}

class PaymentProtectionProxy(private val realPayment: Payment) : Payment {

override fun pay(transaction: Transaction) {
if (!transaction.isInternational){
if (!transaction.isInternational) {
realPayment.pay(transaction)
} else {
println("Can't pay international transactions")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package oop.Observer.subscription

import io.kotlintest.matchers.shouldBe
import io.kotlintest.matchers.shouldEqual
import io.kotlintest.specs.WordSpec

class ObserverWithSubscription : WordSpec() {

init {
"SubjectPublish" should {
val observers = mutableListOf<Observer<String>>()
val subject: PublishSubject<String> = PublishSubject(observers)

"register a observer" {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow nice and klean 😏 I like it 👍 🔝

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I was starting with a JUnit test, but how I have created a one file for 3 classes, I prefer use this kind of test to separate differents things, like Subject and Observer 👍

subject.register(Observer("hello world"))
observers.size shouldBe 1
}

"register a observer and notify it" {
val observer = MockObserver("Hello world")
subject.register(observer)
subject.notify("Next")
observer.hasUpdateCalled shouldBe true
observer.value shouldBe "Next"
}

}

"Observable" should {

"call success on subscription" {
var hasCalled: Boolean = false
val observer = Observer("Hello world")
val success: (String) -> Unit = { value ->
hasCalled = true
value shouldBe "Hello world"
}
observer.subscribe(success, { 2 shouldBe 3 })
hasCalled shouldBe true
}

"update value if is subscribed" {
var hasCalled: Boolean = false
val observer = Observer("Hello world")
val update: (String) -> Unit = { value ->
hasCalled = true
value shouldBe "Updated"
}
val subscription = observer.subscribe({}, update)
observer.update("Updated")
hasCalled shouldBe true
subscription.isSubscribed shouldBe true
}


"not update if is not subscribed" {
var hasCalled: Boolean = false
val observer = Observer("Hello world")
val update: (String) -> Unit = { hasCalled = true }
val subscription = observer.subscribe({}, update)
subscription.unregister()
observer.update("Updated")
hasCalled shouldBe false
subscription.isSubscribed shouldBe false
}

"update if was not subscribed but renew the subscription"{
var hasCalled: Boolean = false
val observer = Observer("Hello world")
val update: (String) -> Unit = { value ->
hasCalled = true
value shouldBe "Updated"
}
val subscription = observer.subscribe({}, update)
subscription.unregister()
subscription.register()
observer.update("Updated")
hasCalled shouldBe true
subscription.isSubscribed shouldBe true
}
}
}

}


class MockObserver(value: String) : Observer<String>(value) {

var hasUpdateCalled = false
var value: String = ""

override fun update(value: String) {
this.hasUpdateCalled = true
this.value = value
}
}