likes
comments
collection
share

Android-我对装饰器模式的理解

作者站长头像
站长
· 阅读数 46

需求分析

以下需求本身很简单,也没有这么离谱的产品经理,没必要复杂化,我们更重要的是理解背后的思路。

假设有一个需求:

  1. 随机生成一个复杂的Key,这个Key包含数字和英文。
  2. 完事后第二天产品经理让你去除Key中的数字。
  3. 第三天让你在末尾拼接个HelloWorld
  4. 第四天让你在末尾拼接个时间戳
  5. 。。。。
  6. 第十天让你仅仅在末尾拼接个HelloWorld,再拼接个时间戳
interface IGenerator {
    
    fun createKey(): String
    fun removeNum(key: String): String
    fun appendHelloWorld(key: String): String
    fun appendTime(key: String): String
}

class GeneratorImpl : IGenerator {
    
    private var key: String = ""
    
    override fun createKey(): String {
        key = generate()
        return key
    }

    override fun removeNum(str: String): String {
        //去除数字并返回
        key = str.replace(Regex("\d+"), "")
        return str
    }

    override fun appendHelloWorld(str: String): String {
        key = str + "helloWorld"
        return key
    }

    override fun appendTime(str: String): String {
        key = str + "1999年"
        return key
    }

    private fun generate(): String {
        return "复杂的Key"
    }

}

fun main() {
    val impl: IGenerator = GeneratorImpl()
    val key1 = impl.createKey()
    val key2 = impl.removeNum(key1)
    //....
}

以上代码带来了什么问题?

  1. 代码臃肿:如果需要加的功能更多呢?GeneratorImpl类中的方法会变得冗长
  2. 代码复杂度可能会增加
  3. 不灵活:如果后续需要修改某个或增加新的功能,需要直接修改GeneratorImpl类,违反了开闭原则(对于扩展是开放的,对于修改是封闭的)

装饰器模式

我们先完成第一天和第二天的需求

  1. 随机生成一个复杂的Key,这个Key包含数字和英文。
  2. 完事后第二天产品经理让你去除Key中的数字。
interface IKeyGenerator {

    fun createKey(): String
}
//第一天我们实现的功能,生成了一个Key
class KeyGenerator : IKeyGenerator {

    override fun createKey(): String {
        return generateComplexKey()
    }

    private fun generateComplexKey(): String {
        //随机生成了一个复杂的密钥,包含数字和英文字母
        return "jd3klq5wj1d"
    }
}

//第二天我们在第一天的基础上,去除了Key中的数字,并没有改动任何第一天中代码
class KeyRemoveNumDecorator(private val keyGenerator: IKeyGenerator) : IKeyGenerator {

    override fun createKey(): String {
        val key = keyGenerator.createKey()
        //去除字符串中的数字
        val newKey = key.replace(Regex("\d+"), "")
        return newKey
    }
}

//调用方式
val keyGenerator: IKeyGenerator = KeyGenerator()
val keyDecorator: IKeyGenerator = KeyDecorator(keyGenerator)
val key = keyDecorator.createKey()
println(key)

打印日志
jdklqwjd

如果看过我上一篇关于代理模式的文章 Android-我对代理模式的理解 - 掘金 (juejin.cn),你可能会有感受:这不就和静态代理基本上一毛一样吗?这个我们后面再说。

注释挺详细的,代码也不难理解。

接下来我们完成第三天的需求: 3. 第三天让你在末尾拼接个HelloWorld

新建类
class KeyAppendHelloWorldDecorator(private val iKeyGenerator: IKeyGenerator) : IKeyGenerator {

    override fun createKey(): String {
        val key = iKeyGenerator.createKey()
        return key + "HelloWorld"
    }
}

调用方式
val keyGenerator: IKeyGenerator = KeyGenerator()
val keyRemoveNumDecorator: IKeyGenerator = KeyRemoveNumDecorator(keyGenerator)
val keyAppendHelloWorldDecorator: IKeyGenerator = KeyAppendHelloWorldDecorator(keyRemoveNumDecorator)
val key = keyAppendHelloWorldDecorator.createKey()
println(key)

接下来我们完成第四天的需求: 4. 第四天让你在末尾拼接个时间戳

新建类
class KeyAppendTimeDecorator(private val iKeyGenerator: IKeyGenerator) : IKeyGenerator {

    override fun createKey(): String {
        val key = iKeyGenerator.createKey()
        //伪时间戳
        return key + "2000年12月20号"
    }
}
使用方式
val keyGenerator: IKeyGenerator = KeyGenerator()
val keyRemoveNumDecorator: IKeyGenerator = KeyRemoveNumDecorator(keyGenerator)
val keyAppendHelloWorldDecorator: IKeyGenerator = KeyAppendHelloWorldDecorator(keyRemoveNumDecorator)
val keyAppendTimeDecorator: IKeyGenerator = KeyAppendTimeDecorator(keyAppendHelloWorldDecorator)
println(keyAppendTimeDecorator.createKey())

到目前为止,我们扩展新需求,没改动任何原有代码,符合开闭原则(对于扩展是开放的,对于修改是封闭的)

接下来我们完成第十天的需求: 6. 第十天让你仅仅在末尾拼接个HelloWorld,再拼接个时间戳

仅仅修改了调用的方式
val keyGenerator: IKeyGenerator = KeyGenerator()
val keyAppendHelloWorldDecorator = KeyAppendHelloWorldDecorator(keyGenerator)
val keyAppendTimeDecorator = KeyAppendTimeDecorator(keyAppendHelloWorldDecorator)
val key = keyAppendTimeDecorator.createKey()
println(key)

从第十天的需求来看,如果不是添加新的需求,我们可以仅仅是通过已经存在的功能类进行了自由搭配组合完成了任务,虽然调用的方法略显麻烦些,阅读性差了点意思。

不过也不难理解,首先第一步就是我们需要先生成keyGenerator对象,而不是直接生成key,接着就是拿着对象按顺序塞到你需要的装饰器中,最后再生成key。

装饰器模式和静态代理模式

这两者都在实现上都是通过持有原始功能的对象的引用,在其基础上添加额外的功能。

灵活性:静态代理模式在编译阶段就确定了代理对象和被代理对象的关系,相对固定。装饰器模式可以通过任意的组合多个装饰器,实现不同的行为组合。

针对性:在我上一篇文章代理模式中,我举出的例子针对解耦不大相关的功能。而装饰器模式主要针对是解耦相似的功能,使得功能间可以按需组合。

偏向:代理模式相对的更偏向非业务,装饰器模式更偏向业务

功能数量:虽说都是扩展新功能,如果添加新功能的概率低,感觉比较适合代理模式。如果功能多且频繁变动,感觉更适合装饰器模式。

转载自:https://juejin.cn/post/7247698383380693049
评论
请登录