Android设计模式 -- 巧用策略模式告别繁琐的 if...else...

需求

根据后台配置进行不同的广告加载策略,例如有广告 A / B / C,某个时段后台配置播放广告 C,默认播放 A;

普通的实现方式

  1. 创建广告管理类,实现广告加载/播放的控制:
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
class AdManager(adName: String) {
var ad = adName
fun initAd() {
when (ad) {
"A" -> initA()
"B" -> initB()
"C" -> initC()
}
}

fun playAd() {
when (ad) {
"A" -> initA()
"B" -> initB()
"C" -> initC()
}
}

fun stopAd() {"A"
when (ad) {
"A" -> initA()
"B" -> initB()
"C" -> initC()
}
}

private fun initA() {
print("init A")
}
// 代码省略...

private fun playA() {
print("play A")
}
// 代码省略...

private fun stopA() {
print("stop A")
}
// 代码省略...
}
  1. 使用方式:
1
2
3
4
5
6
7
8
class ConcreteAd {
fun main() {
var adManager = AdManager("A")
adManager.initAd()
adManager.playAd()
adManager.stopAd()
}
}

从上面看到,充斥着大量的if…else…(Kotlin 中用的 when 语法),并且耦合度很高,想要增加广告就要在同一个类中进行修改。那么使用策略模式来进行优化后,大致是这样的:

  1. 创建广告策略接口 IAdStrategy 类:
1
2
3
4
5
interface IAdStrategy {
abstract fun initAd()
abstract fun playAd()
abstract fun stopAd()
}
  1. 针对不同的广告进行策略的实现(下面以广告A为例):
1
2
3
4
5
6
7
8
9
10
11
12
13
class A : IAdStrategy {
override fun initAd() {
print("init A")
}

override fun playAd() {
print("play A")
}

override fun stopAd() {
print("stop A")
}
}
  1. 创建策略相关的Context来绑定广告和策略接口之间的关系:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class AdStrategyContext {

private lateinit var mAdStrategy: IAdStrategy

constructor(adStrategy: IAdStrategy) {
this.mAdStrategy = adStrategy
}

fun initAd() {
mAdStrategy.initAd()
}

fun playAd() {
mAdStrategy.playAd()
}
}
  1. 使用方式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class ConcreteAd {
fun main() {
// 普通
var adManager = AdManager("A")
adManager.initAd()
adManager.playAd()
adManager.stopAd()

// 策略模式
var adCtx = AdStrategyContext(A())
adCtx.initAd()
adCtx.playAd()
adCtx.stopAd()
}
}

上面的例子可以看到,一旦需要增加广告D的话,去实现对应的 IAdStrategy 接口即可,和之前的代码没有耦合,符合设计原则。但缺点就是如果广告很多的话,会存在很多类文件,并且一旦接口需要补充和修改,那么所有的实现类都会变动。