目录
一、结构型模式
1.1、装饰者模式
1.1.1、概念
装饰者模式就是指在不改变现有对象结构的情况下,动态的给该对象增加一些职责(增加额外功能)的模式.
例如,在一个博客系统中,有时候你希望对方关注你后才能查看你的文章,或者是对方因为你的文章充值了 vip 后才可以查看你的文章,那么此时就可以使用装饰者模式,通过判断用户的权限,动态的给文章增加职责.
装饰者模式中的角色如下:
- 抽象组件:定义一个抽象接口用来规范附加的对象.
- 具体组件:实现抽象构件,将来会被添加一些职责).
- 抽象装饰者:继承抽象构件 和 持有抽象构件的引用,可以通过 子类 扩展具体的构件.
- 具体装饰者:继承抽象装饰,重写相关方法,给具体的构件对象添加附加责任.
1.1.2、案例实现1
需求:实现一个咖啡商店系统,咖啡可以动态的加糖加奶.
//抽象组件
interface Coffee {
fun getDesc(): String
fun getCost(): Double
}
//具体组件
class SimpleCoffee: Coffee {
override fun getDesc(): String = "[ simple coffee ]"
override fun getCost(): Double = 6.0
}
//抽象装饰者
abstract class CoffeeDecorator(
private val coffee: Coffee
): Coffee {
override fun getDesc(): String = coffee.getDesc()
override fun getCost(): Double = coffee.getCost()
}
//具体装饰者
class MikeDecorator(
coffee: Coffee
): CoffeeDecorator(coffee) {
override fun getDesc(): String = "${coffee.getDesc()}, mike"
override fun getCost(): Double = coffee.getCost() + 2.0
}
//具体装饰者
class SugarDecorator(
coffee: Coffee
): CoffeeDecorator(coffee) {
override fun getDesc(): String = "${coffee.getDesc()}, sugar"
override fun getCost(): Double = coffee.getCost() + 1.0
}
fun main() {
val simpleCoffee = SimpleCoffee()
println("simpleCoffee:")
println("desc: ${simpleCoffee.getDesc()}")
println("cost: ${simpleCoffee.getCost()}")
//加奶
val mikeSimpleCoffee = MikeDecorator(simpleCoffee)
println("mikeSimpleCoffee:")
println("desc: ${mikeSimpleCoffee.getDesc()}")
println("cost: ${mikeSimpleCoffee.getCost()}")
//加糖
val mikeSugarSimpleCoffee = SugarDecorator(mikeSimpleCoffee)
println("mikeSugarSimpleCoffee:")
println("desc: ${mikeSugarSimpleCoffee.getDesc()}")
println("cost: ${mikeSugarSimpleCoffee.getCost()}")
}
执行结果如下:
1.1.3、案例实现2
a)BlogShow 接口定义了一个博客展示的基础功能,BaseBlogShow 进行了实现.
//抽象构建角色
interface BlogShow {
fun getTitle(): String
fun getContent(): String
fun display()
}
//具体构建角色
data class BaseBlogShow(
private val title: String,
private val content: String
): BlogShow {
override fun getTitle() = title
override fun getContent() = content
override fun display() {
println("title: $title")
println("content: $content")
}
}
b)BlogShowDecorator 是抽象装饰者,定义了规范,并且持有 blogShow 对象(抽象构建对象).
FollowDecorator 和 VipDecorator 是具体装饰者,将来 BaseBlogShow 对象要进行动态扩展的时候,就可以将 BaseBlogShow 对象作为 具体装饰者的构造参数,动态扩展.
//抽象装饰角色
abstract class BlogShowDecorator(
protected val blogShow: BlogShow
): BlogShow {
override fun getTitle() = blogShow.getTitle()
override fun getContent() = blogShow.getContent()
override fun display() = blogShow.display()
}
//具体装饰角色
class FollowDecorator(
blogShow: BlogShow
): BlogShowDecorator(blogShow) {
override fun display() {
val title = super.getTitle()
val content = if(super.getContent().length > 60)
super.getContent().substring(0, 60).plus("...")
else
super.getContent()
println("title: $title")
println("content: $content")
println("> 关注作者,查看更多内容!")
}
}
//具体装饰角色
class VipDecorator(
blogShow: BlogShow
): BlogShowDecorator(blogShow) {
override fun display() {
val title = super.getTitle()
val content = if(super.getContent().length > 60)
super.getContent().substring(0, 60).plus("...")
else
super.getContent()
println("title: $title")
println("content: $content")
println("> 充值 vip,查看更多内容!")
}
}
c)使用如下
fun main() {
//假设从数据库中拿到数据
val dbBlog = BaseBlogShow("Kotlin (programming language)", "Kotlin is a cross-platform, statically typed, general-purpose high-level programming language with type inference. Kotlin is designed to interoperate fully")
//这里根据用户的权限来给文章进行不同的内容
//...
//假设用户未关注对方,但是对方的文章设置了关注才能访问
//那么此处添加 "关注装饰器"
var blog = FollowDecorator(dbBlog)
//最后给该用户展示
blog.display()
}
运行结果如下
1.1.4、优缺点
优点:
动态扩展:比继承具有更好的扩展性(继承时静态附加责任,装饰者时动态添加责任),可以在不修改原类的情况下,给对象添加责任.
缺点:
增加系统复杂度:装饰者比继承使用的类可能会少,但比继承使用的对象可能更多,更多的对象在程序排查错误的时候可能更复杂.
1.1.5、使用场景
1. 当不能采用继承的方式对程序进行扩展,比如存在大量的独立扩展,为了支持每一种组合产生大量子类,导致子类数目爆炸增长、或者是 类定位为 final 类型(不能继承).
2. 在不影响其他类的情况下,以动态的方式添加责任.