Explorar o código

add iterator pattern

MrOzOn %!s(int64=4) %!d(string=hai) anos
pai
achega
b9ddc1417b

+ 24 - 0
src/behavioral_pattern/README.MD

@@ -51,4 +51,28 @@
 - новые команды добавляются легко, поскольку никакие существующие классы изменять не нужно
 
 
+# [Итератор (Iterator)](./iterator/main.kt)
+
+Это поведенческий паттерн проектирования, который даёт возможность последовательно обходить элементы составных объектов, не раскрывая их внутреннего представления.
+
+## Другое название
+Курсор (Cursor)
+
+## Применимость
+
+- обращение к содержимому агрегированных объектов без раскрытия их внутреннего представления
+- поддержка нескольких активных обходов одного и того же агрегированного объекта
+- предоставление единообразного интерфейса для обхода различных агрегированных структур (то есть для поддержки полиморфной итерации)
+
+## Отношения
+
+Конкретный итератор отслеживает текущий объект в агрегате и может вычислить идущий за ним.
+
+## Результаты
+
+- поддержка разных способов обхода агрегата
+- упрощение интерфейса класса агрегата
+- возможность наличия нескольких активных обходов для данного агрегата
+
+
 

+ 80 - 0
src/behavioral_pattern/iterator/ConcreteIterators.kt

@@ -0,0 +1,80 @@
+package behavioral_pattern.iterator
+
+class FacebookIterator(private val facebook: Facebook, private val type: String, private val email: String): ProfileIterator {
+
+    private var currentPosition = 0
+    private val emails: MutableList<String> = mutableListOf()
+    private val profiles: MutableList<Profile?> = mutableListOf()
+
+    private fun lazyLoad(){
+        if(emails.isEmpty()) {
+            val facebookProfiles = facebook.requestProfileFriendsFromFacebook(email, type)
+            facebookProfiles.forEach { profile ->
+                emails.add(profile)
+                profiles.add(null)
+            }
+        }
+    }
+
+    override fun hasNext(): Boolean {
+        lazyLoad()
+        return currentPosition < emails.size
+    }
+
+    override fun getNext(): Profile? {
+        if(!hasNext())
+            return null
+        val friendEmail = emails[currentPosition]
+        var friendProfile = profiles[currentPosition]
+        if (friendProfile==null){
+            friendProfile = facebook.requestProfileFromFacebook(friendEmail)
+            profiles.set(currentPosition, friendProfile)
+        }
+        currentPosition++
+        return friendProfile
+    }
+
+    override fun reset() {
+        currentPosition = 0
+    }
+
+}
+
+class LinkedInIterator(private val linkedIn: LinkedIn, private val type: String, private val email: String): ProfileIterator {
+    private var currentPosition = 0
+    private val emails: MutableList<String> = mutableListOf()
+    private val profiles: MutableList<Profile?> = mutableListOf()
+
+    private fun lazyLoad(){
+        if(emails.isEmpty()) {
+            val facebookProfiles = linkedIn.requestRelatedContactsFromLinkedInAPI(email, type)
+            facebookProfiles.forEach { profile ->
+                emails.add(profile)
+                profiles.add(null)
+            }
+        }
+    }
+
+    override fun hasNext(): Boolean {
+        lazyLoad()
+        return currentPosition < emails.size
+    }
+
+    override fun getNext(): Profile? {
+        if(!hasNext())
+            return null
+        val friendEmail = emails[currentPosition]
+        var friendProfile = profiles[currentPosition]
+        if (friendProfile==null){
+            friendProfile = linkedIn.requestContactInfoFromLinkedInAPI(friendEmail)
+            profiles.set(currentPosition, friendProfile)
+        }
+        currentPosition++
+        return friendProfile
+    }
+
+    override fun reset() {
+        currentPosition = 0
+    }
+
+}

+ 76 - 0
src/behavioral_pattern/iterator/ConcreteSocialNetworks.kt

@@ -0,0 +1,76 @@
+package behavioral_pattern.iterator
+
+class LinkedIn(cache: List<Profile>?): SocialNetwork {
+    private val contacts: List<Profile> = cache ?: emptyList()
+
+    fun requestRelatedContactsFromLinkedInAPI(profileEmail: String, contactType: String): List<String> {
+        simulateNetworkLatency()
+        println("LinkedIn: Loading \"$contactType\" list of \"$profileEmail\" over the network...")
+        val profile = findContact(profileEmail)
+        return profile?.getContacts(contactType) ?: emptyList()
+    }
+
+    fun requestContactInfoFromLinkedInAPI(profileEmail: String): Profile? {
+        simulateNetworkLatency()
+        println("LinkedIn: loading profile \"$profileEmail\" over the network...")
+        return findContact(profileEmail)
+    }
+
+    private fun findContact(profileEmail: String): Profile? {
+        return contacts.find { profile ->
+            profile.email == profileEmail
+        }
+    }
+
+    override fun createFriendsIterator(profileEmail: String): ProfileIterator =
+        LinkedInIterator(this, "friends", profileEmail)
+
+    override fun createCoworkersIterator(profileEmail: String): ProfileIterator =
+        LinkedInIterator(this, "coworkers", profileEmail)
+
+    private fun simulateNetworkLatency() {
+        try {
+            Thread.sleep(2500)
+        } catch (ex: InterruptedException) {
+            ex.printStackTrace()
+        }
+    }
+
+}
+
+class Facebook(cache: List<Profile>?): SocialNetwork {
+    private val profiles: List<Profile> = cache ?: emptyList()
+
+    fun requestProfileFriendsFromFacebook(profileEmail: String, contactType: String): List<String> {
+        simulateNetworkLatency()
+        println("Facebook: Loading \"$contactType\" list of \"$profileEmail\" over the network...")
+        val profile = findProfile(profileEmail)
+        return profile?.getContacts(contactType) ?: emptyList()
+    }
+
+    private fun simulateNetworkLatency() {
+        try {
+            Thread.sleep(2500)
+        } catch (ex: InterruptedException) {
+            ex.printStackTrace()
+        }
+    }
+
+    fun requestProfileFromFacebook(profileEmail: String): Profile? {
+        simulateNetworkLatency()
+        println("Facebook: loading profile \"$profileEmail\" over the network...")
+        return findProfile(profileEmail)
+    }
+
+    private fun findProfile(profileEmail: String): Profile? {
+        return profiles.find { profile ->
+            profile.email == profileEmail
+        }
+    }
+
+    override fun createFriendsIterator(profileEmail: String): ProfileIterator =
+        FacebookIterator(this,"friends", profileEmail)
+
+    override fun createCoworkersIterator(profileEmail: String): ProfileIterator =
+        FacebookIterator(this,"coworkers", profileEmail)
+}

+ 25 - 0
src/behavioral_pattern/iterator/Profile.kt

@@ -0,0 +1,25 @@
+package behavioral_pattern.iterator
+
+class Profile(val email: String, name: String, vararg contacts: String) {
+
+    private val contacts: MutableMap<String, MutableList<String>> = mutableMapOf()
+
+    init {
+        contacts.forEach { contact ->
+            val parts = contact.split(":")
+            var contactType = "friend"
+            var contactEmail = ""
+            if (parts.size==1){
+                contactEmail = parts[0]
+            } else {
+                contactType = parts[0]
+                contactEmail = parts[1]
+            }
+            if (!this.contacts.containsKey(contactType)) {
+                this.contacts[contactType] = mutableListOf()
+            }
+            this.contacts[contactType]?.add(contactEmail)
+        }
+    }
+    fun getContacts(contactType: String): List<String>? = contacts[contactType]?.toList()
+}

+ 7 - 0
src/behavioral_pattern/iterator/ProfileIterator.kt

@@ -0,0 +1,7 @@
+package behavioral_pattern.iterator
+
+interface ProfileIterator {
+    fun hasNext(): Boolean
+    fun getNext(): Profile?
+    fun reset()
+}

+ 6 - 0
src/behavioral_pattern/iterator/SocialNetwork.kt

@@ -0,0 +1,6 @@
+package behavioral_pattern.iterator
+
+interface SocialNetwork {
+    fun createFriendsIterator(profileEmail: String): ProfileIterator
+    fun createCoworkersIterator(profileEmail: String): ProfileIterator
+}

+ 38 - 0
src/behavioral_pattern/iterator/SocialSpammer.kt

@@ -0,0 +1,38 @@
+package behavioral_pattern.iterator
+
+import java.lang.NullPointerException
+
+class SocialSpammer(private val socialNetwork: SocialNetwork) {
+
+    var iterator: ProfileIterator? = null
+
+    fun sendSpamToFriends(profileEmail: String, message: String) {
+        println("Iterating over friends...")
+        iterator = socialNetwork.createFriendsIterator(profileEmail)
+        if (iterator==null) {
+            throw NullPointerException("iterator is null")
+        }
+        while (iterator!!.hasNext()) {
+            val profile = iterator!!.getNext()
+            sendMessage(profile?.email,message)
+        }
+    }
+
+    fun sendSpamToCoworkers(profileEmail: String, message: String) {
+        println("Iterating over coworkers...")
+        iterator = socialNetwork.createCoworkersIterator(profileEmail)
+        if (iterator==null) {
+            throw NullPointerException("iterator is null")
+        }
+        while (iterator!!.hasNext()) {
+            val profile = iterator!!.getNext()
+            sendMessage(profile?.email,message)
+        }
+    }
+
+    private fun sendMessage(email: String?, message: String) {
+        email?.let {
+            println("Sent message to: '$email'. Message body: '$message'")
+        }
+    }
+}

+ 30 - 0
src/behavioral_pattern/iterator/main.kt

@@ -0,0 +1,30 @@
+package behavioral_pattern.iterator
+
+fun main(){
+    println("LinkedIn")
+    var socialNetwork: SocialNetwork  = LinkedIn(createTestProfiles())
+    var socialSpammer = SocialSpammer(socialNetwork)
+    socialSpammer.sendSpamToFriends("anna.smith@bing.com",
+        "Hey! This is Anna's friend Josh. Can you do me a favor and like this post [link]?")
+    socialSpammer.sendSpamToCoworkers("anna.smith@bing.com",
+        "Hey! This is Anna's boss Jason. Anna told me you would be interested in [link].")
+    println("\nFacebook")
+    socialNetwork = Facebook(createTestProfiles())
+    socialSpammer = SocialSpammer(socialNetwork)
+    socialSpammer.sendSpamToFriends("anna.smith@bing.com",
+        "Hey! This is Anna's friend Josh. Can you do me a favor and like this post [link]?")
+    socialSpammer.sendSpamToCoworkers("anna.smith@bing.com",
+        "Hey! This is Anna's boss Jason. Anna told me you would be interested in [link].")
+
+}
+
+fun createTestProfiles(): List<Profile> {
+    val data = mutableListOf<Profile>()
+    data.add(Profile("anna.smith@bing.com", "Anna Smith", "friends:mad_max@ya.com", "friends:catwoman@yahoo.com", "coworkers:sam@amazon.com"))
+    data.add(Profile("mad_max@ya.com", "Maximilian", "friends:anna.smith@bing.com", "coworkers:sam@amazon.com"))
+    data.add(Profile("bill@microsoft.eu", "Billie", "coworkers:avanger@ukr.net"))
+    data.add(Profile("avanger@ukr.net", "John Day", "coworkers:bill@microsoft.eu"))
+    data.add(Profile("sam@amazon.com", "Sam Kitting", "coworkers:anna.smith@bing.com", "coworkers:mad_max@ya.com", "friends:catwoman@yahoo.com"))
+    data.add(Profile("catwoman@yahoo.com", "Liza", "friends:anna.smith@bing.com", "friends:sam@amazon.com"))
+    return data.toList()
+}