带你了解代理模式、委托模式与策略模式

1,288 阅读6分钟

5分钟带你了解代理模式、委托模式与策略模式

1、前言

脑袋有点痒痒,之前说过策略模式,小伙伴觉得和容易和代理模式混淆,干脆我们一起来看看代理模式、委托模式与策略模式吧。如果您有任何疑问、对文章写的不满意、发现错误或者有更好的方法,欢迎在评论、私信或邮件中提出,非常感谢您的支持。🙏

2、介绍

先来看看三者的概括

代理模式是一种结构型设计模式,它允许在不改变原始对象的基础上为其添加新功能。代理通常与被代理对象实现相同的接口,并在需要的时候将方法调用传递给被代理对象。代理的主要优点是可以在不改变原始对象的情况下添加新功能,以及实现懒加载、安全控制等特性。

委托模式是一种结构型设计模式,它通过将对象的部分行为或属性委托给另一个对象来实现。与代理模式不同,委托模式关注的是对象的行为委托,而不是代理实现新功能。在Kotlin中,可以使用by关键字轻松实现委托模式。

策略模式是一种行为型设计模式,它定义了一系列算法,将每个算法封装到具有公共接口的独立类中,使得它们可以相互替换。策略模式可以在运行时根据需要选择不同的算法,而不需要修改原始代码。

3、同一个用例

假设我们需要开发一个简单的文本编辑器,该编辑器可以读取和保存文件。

(1)代理模式实现(Proxy Pattern)

interface TextEditor {
    fun read(): String
    fun save(content: String)
}

class SimpleTextEditor : TextEditor {
    override fun read(): String {
        return "读取文件内容"
    }

    override fun save(content: String) {
        println("保存文件内容: $content")
    }
}

class TextEditorProxy(private val textEditor: TextEditor) : TextEditor {
    private fun checkAccess(): Boolean {
        // 检查用户是否具有访问权限
        return true
    }

    override fun read(): String {
        return if (checkAccess()) {
            textEditor.read()
        } else {
            "没有读取权限"
        }
    }

    override fun save(content: String) {
        if (checkAccess()) {
            textEditor.save(content)
        } else {
            println("没有保存权限")
        }
    }
}

fun main() {
    val editor = SimpleTextEditor()
    val proxy = TextEditorProxy(editor)

    println(proxy.read())
    proxy.save("新文件内容")
}

(2)委托模式实现(Delegation Pattern)

interface FileSystem {
    fun readFile(): String
    fun writeFile(content: String)
}

class LocalFileSystem : FileSystem {
    override fun readFile(): String {
        return "从本地文件系统读取文件内容"
    }

    override fun writeFile(content: String) {
        println("将文件内容保存到本地文件系统: $content")
    }
}

class CloudFileSystem : FileSystem {
    override fun readFile(): String {
        return "从云文件系统读取文件内容"
    }

    override fun writeFile(content: String) {
        println("将文件内容保存到云文件系统: $content")
    }
}

class DelegatedTextEditor(private val fileSystem: FileSystem) : FileSystem by fileSystem

fun main() {
    val localFileSystem = LocalFileSystem()
    val cloudFileSystem = CloudFileSystem()

    val localEditor = DelegatedTextEditor(localFileSystem)
    val cloudEditor = DelegatedTextEditor(cloudFileSystem)

    println(localEditor.readFile())
    localEditor.writeFile("新文件内容")

    println(cloudEditor.readFile())
    cloudEditor.writeFile("新文件内容")
}

(3)策略模式实现(Strategy Pattern)

interface FileSystemStrategy {
    fun readFile(): String
    fun writeFile(content: String)
}

class LocalFileSystemStrategy : FileSystemStrategy {
    override fun readFile(): String {
        return "从本地文件系统读取文件内容"
    }

    override fun writeFile(content: String) {
        println("将文件内容保存到本地文件系统: $content")
    }
}

class CloudFileSystemStrategy : FileSystemStrategy {
    override fun readFile(): String {
        return "从云文件系统读取文件内容"
    }

    override fun writeFile(content: String) {
        println("将文件内容保存到云文件系统: $content")
    }
}

class StrategyTextEditor(private val strategy: FileSystemStrategy) {
    fun readFile(): String {
        return strategy.readFile()
    }

    fun writeFile(content: String) {
        strategy.writeFile(content)
    }
}

fun main() {
    val localFileSystem = LocalFileSystemStrategy()
    val cloudFileSystem = CloudFileSystemStrategy()

    val editor = StrategyTextEditor(localFileSystem)
    println(editor.readFile())
    editor.writeFile("新文件内容")

    val editor2 = StrategyTextEditor(cloudFileSystem)
    println(editor2.readFile())
    editor2.writeFile("新文件内容")
}

看到这儿,我知道你肯定,捏紧拳头,内心忍不住吐槽。“这TM不都一模一样吗,更晕了”,的确三个例子看起来非常相似,这是因为我们使用相同的需求来展示不同设计模式的应用。

让我们再次回顾这三个设计模式的关键区别:

  1. 代理模式:核心目标是在不修改原始对象的基础上添加新功能,如访问控制。在示例中,TextEditorProxy在执行读取或保存操作之前检查用户是否具有相应的权限。代理对象的主要目的是控制对原始对象的访问。
  2. 委托模式:核心目标是将对象的部分行为或属性委托给另一个对象,以实现关注点分离和代码复用。在示例中,DelegatedTextEditor通过委托将读取和保存文件的行为委托给不同的文件系统。委托模式关注的是通过组合关系来实现功能的重用。
  3. 策略模式:核心目标是在运行时选择不同的算法或行为。在示例中,StrategyTextEditor接受一个FileSystemStrategy实例,然后根据提供的策略来读取和保存文件。策略模式主要关注的是在运行时选择不同的算法或行为。

它们之间的关键区别在于设计模式的核心目标和如何实现这些目标

可以将这三者视为具有相似结构的不同设计模式,它们确实在某些方面具有相似性,但因为它们的核心目标和应用场景不同,所以它们被归类为不同的设计模式。

4、加深印象

值得注意的是,因为其应用场景的不同,如代理模式,它充当了客户端和实际对象之间的中介。代理对象控制客户端的访问,并在必要时将请求传递给实际对象。代理模式的目的是提供一个代替实际对象的占位符,以便控制对实际对象的访问。

而策略模式它定义了一系列算法,将每个算法都封装在一个独立的类中,并使它们可以互换。策略模式的目的是在运行时选择一种算法。

在策略模式中,没有代理类或中介对象,因为策略模式的重点是在运行时选择不同的算法,而不是在对象之间添加额外的层级或中介。

所以说策略模式中没有代理类或中介对象是合理的,而代理模式是一种结构型模式,它包括代理类和中介对象。

但是如果硬要深究,其实就是换个说法罢了(歪理)

5、总结

在代理模式中,代理对象和实际对象具有相同的接口;而在策略模式中,策略对象通常都实现一个共同的策略接口。在委托模式中,委托对象可以根据需要实现相同或不同的接口。

也可以这么说

  1. 代理模式:寻找具有相同接口的代理对象和实际对象。代理对象通常将请求转发给实际对象,或在转发请求之前/之后执行一些额外操作。
  2. 委托模式:注意对象之间的委托关系。委托对象将某些操作委托给另一个对象执行。在 Kotlin 中,这种关系通常通过 by 关键字表示。
  3. 策略模式:寻找一组具有共同接口的策略类。客户端通常将这些策略类作为参数传递给上下文对象,以便在运行时选择合适的策略。

6、结尾

写这玩意,有点烧脑子,不过大概是这么个意思了,如果有什么奇奇怪怪的东西,请怪我的猫。如果您有任何疑问、对文章写的不满意、发现错误或者有更好的方法,欢迎在评论、私信或邮件中提出,非常感谢您的支持。🙏

img

7、感谢

  1. 校稿:ChatGpt/Bing
  2. 文笔优化:ChatGpt/Bing/秘塔写作猫