0%

责任链模式

一个请求可能需要经过多个步骤处理

例子:组合过滤器

1
2
3
4
5
6
7
8
9
abstract class Filter {
protected lateinit var next: Filter

fun setFilter(filter: Filter) {
next = filter
}

abstract fun doFilter(): Boolean
}

纯的责任链模式

处理器的操作只有两种:

  1. 处理事务然后结束
  2. 不处理事务,将事务传给下一个处理器

保证至少有一个处理器是有作用的

例子:公司请假

请假小于1天,组领导可批,小于3天,部门领导可批,大于3天的需要大boss批

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class GroupLeaderFilter(private val day: Int) : Filter() {
override fun doFilter(): Boolean = when {
day <= 1 -> true
else -> next.doFilter()
}
}

class DeptLeaderFilter(private val day: Int) : Filter() {
override fun doFilter(): Boolean = when {
day <= 3 -> true
else -> next.doFilter()
}
}

class FinalLeaderFilter(private val day: Int) : Filter() {
override fun doFilter(): Boolean = when {
day <= 7 -> true
else -> false
}
}

不纯的责任链模式

处理器的操作是任意的:

  • 可以处理完事务后结束
  • 也可以不处理事务直接结束
  • 可以不处理事务传给下一个处理器
  • 也可以处理完事务再传给下一个处理器

例子:公司报销

公司申请报销需要组内领导、部门领导、大boss依次审批通过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class GroupLeaderFilter() : Filter() {
override fun doFilter(): Boolean {
println("group leader ok")
return next.doFilter()
}
}

class DeptLeaderFilter() : Filter() {
override fun doFilter(): Boolean {
println("department leader ok")
return next.doFilter()
}
}

class FinalLeaderFilter() : Filter() {
override fun doFilter(): Boolean {
println("final leader ok")
return true
}
}

观察者模式

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新

实现

1
2
3
4
5
╭─────────────╮  Fire Event  ╭──────────────╮
│ │─────────────>│ │
│ Subject │ │ Observer │
│ │<─────────────│ │
╰─────────────╯ Subscribe ╰──────────────╯
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
interface Observer {
fun exec()

fun subscribe(subject: Subject)
}

// 被观察者
abstract class Subject {
protected val observers = ArrayList<Observer>()

abstract fun notifyObserver()

fun addObserver(observer: Observer) = observers.add(observer)
}

class ConcreteObserverA : Observer {
override fun exec() = println("A exec!")

override fun subscribe(subject: Subject) {
subject.addObserver(this)
}
}

class ConcreteObserverB : Observer {
override fun exec() = println("B exec!")

override fun subscribe(subject: Subject) {
subject.addObserver(this)
}
}

class ConcreteSubject : Subject() {
override fun notifyObserver() = observers.forEach { it.exec() }
}

fun main() {
val objA = ConcreteObserverA()
val objB = ConcreteObserverB()
val sub = ConcreteSubject()

objA.subscribe(sub) // A 要观察 sub
objB.subscribe(sub) // B 要观察 sub

sub.notifyObserver() // sub 发生变化,通知 A,B 发生了变化
}

发布订阅模式

为了解耦

1
2
3
4
5
╭─────────────╮                 ╭───────────────╮   Fire Event   ╭──────────────╮
│ │ Publish Event │ │───────────────>│ │
│ Publisher │────────────────>│ Event Channel │ │ Subscriber │
│ │ │ │<───────────────│ │
╰─────────────╯ ╰───────────────╯ Subscribe ╰──────────────╯
1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface Subscriber {
fun exec()
}

interface Publisher

class DataHub {
private val map = HashMap<Publisher, LinkedList<Subscriber>>()

fun subscribe(publisher: Publisher, subscriber: Subscriber) =
map.getOrPut(publisher) { LinkedList() }.add(subscriber)

fun publish(publisher: Publisher) = map.getOrPut(publisher) { LinkedList() }.forEach { it.exec() }
}

模板模式

一些方法通用,却在每一个子类都重新写了这一方法。

例子:游戏流程

所有游戏都是准备、开始、结束这三个步骤,只是不同游戏不同操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public abstract class Game {
abstract void initialize();
abstract void startPlay();
abstract void endPlay();

//模板
public final void play(){

//初始化游戏
initialize();

//开始游戏
startPlay();

//结束游戏
endPlay();
}
}

public class Football extends Game {} // 足球的实现
public class Basketball extends Game {} // 篮球的实现

策略模式

有一个方法,该方法对应多个策略去执行,可把该方法写为接口,不同策略按自己的写法去执行,然后用一个上下文去执行

例子:商品打折

商品打折策略:不打折、打折、满减

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
interface DiscountStrategy {
fun getDiscount(total: BigDecimal): BigDecimal
}

// 会员打折
class UserDiscountStrategy : DiscountStrategy {
override fun getDiscount(total: BigDecimal): BigDecimal =
total.multiply(BigDecimal(0.1)).setScale(2, RoundingMode.DOWN)
}

// 满减
class OverDiscountStrategy : DiscountStrategy {
override fun getDiscount(total: BigDecimal): BigDecimal =
if (total >= BigDecimal(100)) BigDecimal(20) else BigDecimal.ZERO
}

// 上下文类,注入策略
class DiscountContext(
private val discountStrategy: DiscountStrategy
) {
fun getPrice(total: BigDecimal) = total.subtract(discountStrategy.getDiscount(total).setScale(2))
}

// Client 调用
fun main() {
val ctx = DiscountContext(UserDiscountStrategy())
println(ctx.getPrice(BigDecimal(110)))
}

与简单工厂结合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class DiscountContext(private val strategyName: String) {
private val strategy: DiscountStrategy = when (strategyName) {
"User" -> UserDiscountStrategy()
"Over" -> OverDiscountStrategy()
else -> throw Exception()
}

fun getPrice(total: BigDecimal) = total.subtract(strategy.getDiscount(total).setScale(2))
}

// Client 调用
fun main() {
val ctx = DiscountContext("User")
println(ctx.getPrice(BigDecimal(110)))
}

享元模式

在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。

例子:缓存

该模式主要是写成缓存

1
2
3
4
5
class StudentFactory {
private val map = HashMap<String, Student>()

fun getStudent(key: String) = map.getOrPut(key) { Student() }
}

外观模式

业务层 A 的类想调用业务层 B 的类,如

1
2
3
A1 -> B1、B2、B3
A2 -> B2、B4、B8
....

可设置门面 Facede C,门面 C 管理 B的类,A 层通过 C 调用 B,这样 A 层就不需要考虑 B 层的细节或更改,只需调用 C 即可

例子:去茶馆喝茶

消费者只需要到茶馆下单即可,不需要关心茶是怎么烧的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 业务层 B 的类
class Tea
abstract class Water
abstract class TeaLeaf
abstract class Kettle {
fun boil(water: Water, teaLeaf: TeaLeaf) = Tea()
}

// 门面 C 管理 B 的类
class TeaFacade {
fun makeTea(kettle: Kettle, water: Water, teaLeaf: TeaLeaf) = kettle.boil(water, teaLeaf)
}

// client 通过 TeaFacade 获得茶
fun main() {
TODO("人点单喝茶")
}

装饰模式

为一个类(Component)动态添加其他功能,用装饰模式来动态添加

例子:穿衣服

人穿衣服,不同人有不同衣服搭配方法,甚至穿着顺序也可以不一样,但结果都是穿上了衣服

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
interface ClothComponent {
fun wear()
}

abstract class ClothDecoration(
private val clothComponent: ClothComponent
) : ClothComponent {
override fun wear() = clothComponent.wear()
}

class JackClothDecoration(private val clothComponent: ClothComponent) : ClothDecoration(clothComponent) {
override fun wear() {
super.wear() // 先运行 component 的方法,再处理装饰效果
print(" jack")
}
}

class PantClothDecoration(private val clothComponent: ClothComponent) : ClothDecoration(clothComponent) {
override fun wear() {
super.wear()
print(" pant")
}
}

// Client 要调用的类
class Person(private val name: String) : ClothComponent {
override fun wear() = print("$name wear")
}

fun main() {
val person = JackClothDecoration(
PantClothDecoration(
Person("Tom")
)
)
person.wear() // Tom wear pant jack
}

组合模式

组合多个对象形成树形结构以表示具有 “整体—部分” 关系的层次结构。

组合模式的关键是定义了一个抽象构件类,它既可以代表叶子,又可以代表容器,而客户端针对该抽象构件类进行编程,无须知道它到底表示的是叶子还是容器,可以对其进行统一处理。同时容器对象与抽象构件类之间还建立一个聚合关联关系,在容器对象中既可以包含叶子,也可以包含容器,以此实现递归组合,形成一个树形结构。

例子:文件目录

包含文件夹和文件两种类型

透明组合模式

抽象构件角色中声明了所有用于管理成员对象的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 调用了没有重写的方法时会抛出异常
interface Component {
fun getName(): String = throw UnsupportedOperationException()

fun add(component: Component): Unit = throw UnsupportedOperationException()

fun remove(component: Component): Unit = throw UnsupportedOperationException()

fun print(): Unit = throw UnsupportedOperationException()

fun getContent(): String = throw UnsupportedOperationException()
}

// 文件夹没有内容
class Folder(private val name: String) : Component {
private val componentList = ArrayList<Component>()

override fun getName() = name

override fun add(component: Component) = componentList.add(component)

override fun remove(component: Component) = componentList.remove(component)

override fun print() {
println(getName())
componentList.forEach { it.print() }
}
}

// 文件是叶子节点,不能添加 or 删除文件
class File(
private val name: String,
private val content: String
) : Component {
override fun getName() = name

override fun print() {
println(getName())
}

override fun getContent() = content
}

安全组合模式

在安全组合模式中,只声明了公有方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
interface Component {
fun getName(): String

fun print()
}

class Folder(private val name: String) : Component {
private val componentList = ArrayList<Component>()

override fun getName(): String = name

override fun print() {
println(getName())
componentList.forEach { it.print() }
}

fun add(component: Component) = componentList.add(component)

fun remove(component: Component) = componentList.remove(component)
}

class File(
private val name: String,
private val content: String
) : Component {
override fun getName(): String = name

override fun print() = println(getName())

fun getContent() = content
}

桥接模式

将抽象部分与它的实现部分分离,使它们都可以独立地变化。

例子:汽车生产

汽车有多种品牌,每种品牌有对应自己的引擎器件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/**
* 抽象依赖部分
*/
interface Engine {
fun start()
}

/**
* 高层抽象,Client 直接调用层
*/
abstract class Car(
private val engine: Engine
) {
abstract fun drive()
}

/**
* 高层抽象实现层
*/
abstract class RefinedCar(
private val engine: Engine
) : Car(engine) {

override fun drive() {
engine.start()
}

abstract fun getBrand(): String
}

/**
* 具体实现
*/
class ACar(
private val engine: Engine
) : RefinedCar(engine) {

override fun getBrand(): String = "A"
}

class BEngine : Engine {
override fun start() {
TODO("Not yet implemented")
}
}

fun main() {
val car = ACar(BEngine())
car.drive()
}

当我们需要增加车的品种 or 增加引擎的种类时,只需要实现对应的继承即可,无需修改其他类

适配器模式

把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法一起工作的两个类能够在一起工作。

为什么

现有的类可以满足客户类的功能需要,但是它所提供的接口不一定是客户类所期望的,这可能是因为现有类中方法名与目标类中定义的方法名不一致等原因所导致的。客户才是上帝

类的适配器模式

通过继承类实现接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 我们需要实现这个接口的函数
interface Target {
fun request()
}

// 需要的功能已经在另外的类中实现过了
open class Adaptee {
fun originRequest() {
TODO()
}
}

// 通过 Adapter 匹配
class Adapter : Adaptee(), Target {
override fun request() {
originRequest()
}
}

// Client 调用
fun main() {
val adapter = Adapter()
adapter.request()
}

对象的适配器模式

通过注入实现接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 我们需要实现这个接口的函数
interface Target {
fun request()
}

// 需要的功能已经在另外的类中实现过了
open class Adaptee {
fun originRequest() {
TODO()
}
}

// 通过 Adapter 匹配
class Adapter(
private val adaptee: Adaptee = Adaptee()
) : Target {
override fun request() {
adaptee.originRequest()
}
}

// Client 调用
fun main() {
val adapter = Adapter()
adapter.request()
}