diff --git a/build.gradle b/build.gradle index 1e791b6..8e53d2c 100644 --- a/build.gradle +++ b/build.gradle @@ -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' @@ -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' } diff --git a/src/main/kotlin/oop/Observer/subscription/ObserverWithSubscription.kt b/src/main/kotlin/oop/Observer/subscription/ObserverWithSubscription.kt new file mode 100644 index 0000000..0995512 --- /dev/null +++ b/src/main/kotlin/oop/Observer/subscription/ObserverWithSubscription.kt @@ -0,0 +1,79 @@ +package oop.Observer.subscription + +class PublishSubject(private val observers: MutableList> = mutableListOf()) { + + fun register(observer: Observer): Observer { + observers.add(observer) + return observer + } + + fun notify(value: A) { + observers.forEach { it.update(value) } + } + +} + +open class Observer(private val value: A) { + + private var subscription: Subscription? = null + + open fun update(value: A) { + if (subscription?.isSubscribed ?: false) { + subscription?.update?.invoke(value) + } + } + + fun subscribe(success: (A) -> Unit, update: (A) -> Unit): Subscription { + success(value) + return Subscription(update).also { subscription = it } + } + +} + + +class Subscription internal constructor(internal val update: (A) -> Unit, + internal var isSubscribed: Boolean = true) { + + fun unregister() { + isSubscribed = false + } + + fun register() { + isSubscribed = true + } +} + +fun main(args: Array) { + val success: (String) -> Unit = { println("Value: $it") } + + val subject: PublishSubject = 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() +} diff --git a/src/main/kotlin/oop/Proxy/ProtectionProxy.kt b/src/main/kotlin/oop/Proxy/ProtectionProxy.kt index c6f55f9..8da51aa 100644 --- a/src/main/kotlin/oop/Proxy/ProtectionProxy.kt +++ b/src/main/kotlin/oop/Proxy/ProtectionProxy.kt @@ -1,5 +1,69 @@ package oop.Proxy +interface Car { + 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) { + + + var carVirtualProxy = CarVirtualProxy({ RealCar("tonilopezmr", 5) }) + 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) } @@ -7,7 +71,7 @@ interface Payment { 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") diff --git a/src/test/kotlin/oop/Observer/subscription/ObserverWithSubscription.kt b/src/test/kotlin/oop/Observer/subscription/ObserverWithSubscription.kt new file mode 100644 index 0000000..bf3ba84 --- /dev/null +++ b/src/test/kotlin/oop/Observer/subscription/ObserverWithSubscription.kt @@ -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>() + val subject: PublishSubject = PublishSubject(observers) + + "register a 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(value) { + + var hasUpdateCalled = false + var value: String = "" + + override fun update(value: String) { + this.hasUpdateCalled = true + this.value = value + } +} +