Ver Fonte

add proxy pattern

MrOzOn há 4 anos atrás
pai
commit
1a6bd5549f

+ 29 - 0
src/structural_patterns/README.MD

@@ -160,3 +160,32 @@ _-_
 
 При использовании приспособленцев возможны затраты на передачу, поиск или вычисление внутреннего состояния на стадии выполнения, особенно если раньше оно хранилось как внутреннее. Однако такие затраты с лихвой компенсируются экономией памяти за счет совместного использования объектов-приспособленцев.
 
+# [Заместитель (Proxy)](./proxy/main.kt)
+
+Это структурный паттерн проектирования, который позволяет подставлять вместо реальных объектов специальные объекты-заменители. Эти объекты перехватывают вызовы к оригинальному объекту, позволяя сделать что-то до или после передачи вызова оригиналу.
+Является суррогатом другого объекта и контролирует доступ к нему.
+
+## Другое название
+Cуррогат (Surrogate)
+
+## Применимость
+
+Паттерн _заместитель_ применим во всех случаях, когда возникает необходимость сослаться на объект более гибким или нетривиальным способом, чем при использовании простого указателя.
+В частности:
+- виртуальный заместитель создает «тяжелые» объекты по требованию
+- защищающий заместитель контролирует доступ к исходному объекту
+- «умная» ссылка — это замена обычного указателя. Она позволяет выполнить дополнительные действия при доступе к объекту.
+- загрузку объекта из долгосрочного хранилища в память при первом обращении к нему
+- проверку и установку блокировки на реальный объект при обращении к нему, чтобы никакой другой объект не смог в это время изменить его
+
+## Отношения
+
+Заместитель при необходимости переадресует запросы объекту. Детали зависят от вида заместителя.
+
+## Результаты
+
+С помощью паттерна заместитель при доступе к объекту вводится дополнительный уровень косвенности. У этого подхода есть много вариантов в зависимости от вида заместителя:
+- удаленный заместитель может скрыть тот факт, что объект находится в другом адресном пространстве
+- виртуальный заместитель может выполнять оптимизацию, например создание объекта по требованию
+- защищающий заместитель и «умная» ссылка позволяют решать допол- нительные задачи при доступе к объекту
+

+ 12 - 0
src/structural_patterns/proxy/IThirdPartyYouTubeLib.kt

@@ -0,0 +1,12 @@
+package structural_patterns.proxy
+
+interface IThirdPartyYouTubeLib {
+    fun listVideos(): List<Video>
+    fun getVideoInfo(videoId: String): String
+    fun downloadVideo(videoId: String): Video
+}
+
+class Video(val id: String,
+            val title: String,
+            val duration: Int,
+            val data: ByteArray)

+ 39 - 0
src/structural_patterns/proxy/SomeProxy.kt

@@ -0,0 +1,39 @@
+package structural_patterns.proxy
+
+class CachedYouTubeClass(private val service: IThirdPartyYouTubeLib): IThirdPartyYouTubeLib {
+
+    private val cacheVideoList = mutableMapOf<String, Video>()
+    private val cacheVideoInfo = mutableMapOf<String, String>()
+
+    override fun listVideos(): List<Video> {
+        if (cacheVideoList.isEmpty()) {
+            println("empty cacheVideoList!!!")
+            val list = service.listVideos()
+            list.forEach { video ->
+                cacheVideoList[video.id] = video
+            }
+        }
+        return cacheVideoList.values.toList()
+    }
+
+    override fun getVideoInfo(videoId: String): String {
+        var info = cacheVideoInfo[videoId]
+        if (info==null) {
+            println("video info not found in cache!!!")
+            info = service.getVideoInfo(videoId)
+            cacheVideoInfo[videoId] = info
+        }
+        return info
+    }
+
+    override fun downloadVideo(videoId: String): Video {
+        var video = cacheVideoList[videoId]
+        if (video==null) {
+            println("cache don't contain video, download it and caching")
+            video = service.downloadVideo(videoId)
+            cacheVideoList[videoId] = video
+        }
+        return video
+    }
+
+}

+ 31 - 0
src/structural_patterns/proxy/SomeService.kt

@@ -0,0 +1,31 @@
+package structural_patterns.proxy
+
+import kotlin.random.Random
+
+class ThirdPartyYouTubeLib: IThirdPartyYouTubeLib {
+
+    override fun listVideos(): List<Video> {
+        println("get videos from network")
+        Thread.sleep(1500)
+        val list: MutableList<Video> = mutableListOf()
+        list.add(Video("123","Title1", 100, "bla-bla-Title1".toByteArray()))
+        list.add(Video("56","Title2", 150, "bla-bla-Title2".toByteArray()))
+        list.add(Video("57","Title3", 300, "bla-bla-Title3".toByteArray()))
+        list.add(Video("387","Title4", 2300, "bla-bla-Title4".toByteArray()))
+        list.add(Video("33","Title5", 230, "bla-bla-Title5".toByteArray()))
+        return list
+    }
+
+    override fun getVideoInfo(videoId: String): String {
+        println("get video info by id from network")
+        Thread.sleep(500)
+        return "Info: videoId=$videoId, title=\"Title$videoId\", duration=${Random.nextInt(0, 1000)}"
+    }
+
+    override fun downloadVideo(videoId: String): Video {
+        println("download video info by id from network")
+        Thread.sleep(3000)
+        return Video(videoId,"Title$videoId", Random.nextInt(0, 1000),
+            "bla-bla-Title$videoId".toByteArray())
+    }
+}

+ 23 - 0
src/structural_patterns/proxy/main.kt

@@ -0,0 +1,23 @@
+package structural_patterns.proxy
+
+fun main(){
+    val videoService = ThirdPartyYouTubeLib()
+    val videoServiceProxy = CachedYouTubeClass(videoService)
+    println("get list videos first time")
+    var videos = videoServiceProxy.listVideos()
+    println("${videos.size} items")
+    println("get list videos second time")
+    videos = videoServiceProxy.listVideos()
+    println("${videos.size} items")
+    println("get info video first time")
+    println(videoServiceProxy.getVideoInfo("111"))
+    println("get info video second time")
+    println(videoServiceProxy.getVideoInfo("111"))
+    println("get video first time")
+    println("downloaded file \"${videoServiceProxy.downloadVideo("911").title}\"")
+    println("get video second time")
+    println("downloaded file \"${videoServiceProxy.downloadVideo("911").title}\"")
+    println("get list videos second time")
+    videos = videoServiceProxy.listVideos()
+    println("${videos.size} items")
+}