设计模式之Kotlin实现(上)

设计模式主要分创建型、结构型、行为型,这篇文章主要记录本人使用Kotlin实现的创建型和结构型的12种设计模式,包括工厂模式、抽象工厂模式、单例模式、原型模式、建造者模式、适配器模式、组合模式、装饰器模式、享元模式、桥接模式、外观模式、静态代理模式。行为型设计模式在下一篇推出。

创建型

工厂模式

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
interface Product {
fun printProductId()
}
abstract class Factory {
fun product(productId: String): Product {
var p = createProduct(productId)
return p
}
protected abstract fun createProduct(productId: String): Product;
}
class Pen(var productId: String) : Product {
override fun printProductId() {
println("该笔的ID是:$productId")
}
}
object PenFactory : Factory() {
override fun createProduct(productId: String): Product {
return Pen(productId)
}
}
fun main(args: Array<String>) {
var oneProduct = PenFactory.product("1024")
oneProduct.printProductId()
}

将工厂抽象出来,每次生成不同ID的相同产品时,使用相同的工厂生产同种产品。

抽象工厂模式

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
interface ProductA {
fun printProductId()
}
interface ProductB {
fun printProductId()
}
abstract class AbstractFactory {
var producta: ProductA? = null
var productb: ProductB? = null
fun product(id01: String?, id02: String?) {
producta = createProductA(id01)
productb = createProductB(id02)
}
abstract fun createProductA(id: String?): ProductA
abstract fun createProductB(id: String?): ProductB
}
class CompA_ProductA(var id: String?) : ProductA {
override fun printProductId() {
id?.let {println("组合A的产品A的ID是:$it")}
?: println("没有生产组合A的产品A")
}
}
class CompA_ProductB(var id: String?) : ProductB {
override fun printProductId() {
id?.let {println("组合A的产品B的ID是:$it")}
?: println("没有生产组合A的产品B")
}
}
class CompB_ProductA(var id: String) : ProductA {
override fun printProductId() {
println("组合B的产品A的ID是:$id")
}
}
class CompB_ProductB(var id: String) : ProductB {
override fun printProductId() {
println("组合B的产品B的ID是:$id")
}
}
class CompAFactory(id01: String?, id02: String?) : AbstractFactory() {
init {
super.product(id01, id02)
}
override fun createProductA(id: String?): ProductA {
return CompA_ProductA(id)
}
override fun createProductB(id: String?): ProductB {
return CompA_ProductB(id)
}
}
fun main(args: Array<String>) {
var compAFactory = CompAFactory("01", null)
var compA_ProductA = compAFactory.producta
var compA_ProductB = compAFactory.productb
compA_ProductA?.printProductId()
compA_ProductB?.printProductId()
}

每次生成不同ID的相同产品族(比如这里可以指CompA_ProductA、CompA_ProductB构成的族等),使用相同工厂(这里指CompAFactory)生产同一族产品。

单例模式

原型模式

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
51
52
53
open class Fruitprototype : Cloneable
class FruitImpl : Fruitprototype {
var name: String?
var orange: Orangeprototype?
constructor(name: String, orange: Orangeprototype) {
this.name = name
this.orange = orange
}
fun getClone(): FruitImpl? {
var fruit: FruitImpl? = null
try {
fruit = super.clone() as FruitImpl
// 对内部引用对象进行拷贝操作
fruit.orange = this.orange?.getClone()
} catch (e: CloneNotSupportedException) {
e.printStackTrace()
}
return fruit
}
}
class Orangeprototype : Fruitprototype {
var name: String?
var id: Int?
constructor(name: String, id: Int) {
this.name = name
this.id = id
}
fun getClone(): Orangeprototype? {
var orange: Orangeprototype? = null
try {
orange = super.clone() as Orangeprototype
} catch (e: CloneNotSupportedException) {
e.printStackTrace()
}
return orange
}
}
fun main(args: Array<String>) {
val orange01 = Orangeprototype("orange01", 1)
val fruit01 = FruitImpl("fruit01", orange01)
val fruit02 = fruit01.getClone()
(fruit02 as FruitImpl).orange?.let { it.id = 2 }
fruit02.orange?.let { it.name = "orange02" }
println(orange01.id.toString() + " " + orange01.name)
}

程序具体分析见本站之前的原型模式相关文章。

换了一种方式来写类的构造器,可见如果类名后没有显式添加(),那么constructor方法不用写返回类型,而创建类的对象时不能省略参数。

Java里面采用super.clone()是因为对象调用clone()实际是委托了Object类的clone(),具体可以见文章最后的参考,Kotlin应该类似。

如果Fruitprototype声明为接口,那么运行时会报错,目前没有找到具体原因。

建造者模式

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
class BuilderProduct {
val color: String?
val id: Int
val size: Int
companion object Builder {
private var color: String? = null
private var id: Int = 0
private var size: Int = 0
fun builderColor(color: String): Builder {
this.color = color
return this
}
fun builderId(id: Int): Builder {
this.id = id
return this
}
fun builderSize(size: Int): Builder {
this.size = size
return this
}
fun build(): BuilderProduct {
return BuilderProduct(this)
}
}
private constructor(builder: Builder) {
this.color = builder.color
this.id = builder.id
this.size = builder.size
}
}
fun main(args: Array<String>) {
var builderProduct = BuilderProduct.Builder.builderColor("Red")
.builderId(1).builderSize(5000).build()
println(builderProduct.size)
}

这里的建造者模式参照《Effective Java》来实现,有些设计模式的书籍强调建造者、监工、使用者等角色,在这里监工和使用者合二为一,监工表现为代码编写时的方法调用顺序(Builder方法的连环调用)。

结构型

适配器模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
interface Target {
fun targetMathod()
}
class Adaptee {
fun adapteeMethod() {
println("我是adaptee!")
}
}
class Adapter(var adaptee: Adaptee) : Target{
override fun targetMathod() {
adaptee.adapteeMethod()
}
}
fun main(args: Array<String>) {
var ada = Adapter(Adaptee()) as Target
ada.targetMathod()
}

有委托的实现方式就不采用继承,最后的as Target说明适配成功,可以应用在使用Target的场景。

组合模式

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
abstract class Component(open var size: Int) {
abstract fun getId(): String
override fun toString(): String {
return "${getId()}大小为:${size}"
}
}
class Leaf(val id: Int, override var size: Int): Component(size) {
override fun getId(): String {
return "ID是${id}的Leaf"
}
}
class Composite(val id: Int, override var size: Int = 0) : Component(size) {
var composite = ArrayList<Component>()
override fun getId(): String {
return "ID是${id}的Composite"
}
fun add(e: Component) {
composite.add(e)
size = composite.size
}
}
fun main(args: Array<String>) {
var component01 = Composite(1)
var component02 = Composite(2)
var component03 = Composite(3)
var component04 = Composite(4)
component01.add(component02)
component02.add(component03)
component02.add(component04)
component02.add(Leaf(11, 100))
println(component01)
println(component02)
}

Leaf、Composite、Component是三个关键角色,Component是Leaf、Composite相似部分的抽象,包括getSize方法,toString方法等。Kotlin和Java的不同之一是Kotlin因为声明的不是字段而是属性,所以涉及到属性的override。

装饰器模式

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
interface DecComponent {
fun DecPrint()
}
class ConcreteComponent : DecComponent {
override fun DecPrint() {
println("我是被装饰的对象!")
}
}
abstract class Decorator(open var decComponent: DecComponent) : DecComponent {}
class ConcreteDecorator(override var decComponent: DecComponent) : Decorator(decComponent) {
override fun DecPrint() {
println("-----我是装饰物-----")
decComponent.DecPrint()
println("-----我是装饰物-----")
}
}
fun main(args: Array<String>) {
var c = ConcreteComponent()
var decorator = ConcreteDecorator(c)
decorator.DecPrint()
}

代理模式和装饰器模式很像,有的时候也没必要分那么细,如果我问自己它们有什么区别,也只会从“哲学”的角度来回答:代理模式侧重“他是他你是你”,而装饰器模式侧重“你始终是你”。代理模式虽然代理了被代理对象的功能,但是终究不应该是原对象,所以需要new一个新的对象,再就是可能代理模式更强调代理动作的同一性吧(代理方法名相同),所以装饰器模式未必需要相同方法名的方法来装饰被装饰的方法。至于功能扩展什么的,从实现效果来看代理模式和装饰器模式都能扩展功能。

享元模式

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
interface FruitFlyweight {
fun printColor()
}
class OrangeFlyweight(var color: String) : FruitFlyweight {
override fun printColor() {
println("$color $this")
}
}
class FruitFactoryFlayweight {
companion object {
val fruitMap = HashMap<String, FruitFlyweight>()
fun getFruitflyweight(color: String): FruitFlyweight {
var flyweight = fruitMap[color]
flyweight = flyweight ?: OrangeFlyweight(color)
fruitMap.put(color, flyweight)
return flyweight
}
}
}
fun main(args: Array<String>) {
FruitFactoryFlayweight.getFruitflyweight("Red").printColor()
FruitFactoryFlayweight.getFruitflyweight("Red").printColor()
}

基本代码和本站之前的文章一样,区别在于使用了伴生对象。在本站其它文章中的解析已经说明,伴生对象内的属性,实际上是外围类的属性,所以fruitMap声明在伴生对象内。

桥接模式

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 Student {
fun study()
fun sleep()
}
// 学生的具体实现
class ChinaStudent: Student {
override fun study() {
println("非常努力!")
}
override fun sleep() {
println("没有时间休息!")
}
}
// 学生参加课外活动功能扩展
open class Activities(private var student: Student) {
fun study() {
student.study()
}
fun sleep() {
student.sleep()
}
}
class ExActivities(var student: Student) : Activities(student) {
fun exActivity() {
if (student is ChinaStudent)
println("中国学生太累不参加活动!")
}
}
fun main(args: Array<String>) {
ExActivities(ChinaStudent()).exActivity()
}

桥接模式在本人看来属于“功能代理实现”,这样新增功能和原本实现可以解耦合。在本例中,学生类的实现在一边,而活动的功能扩展在另一边,最基本的活动“代理”了学生的功能,但是扩展功能并不直接涉及学生类,这样就完成了解耦合。

外观模式

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
class A {
init {
println("我是A!")
}
}
class B
class C
class Facade {
var a: A? = null
var b: B? = null
var c: C? = null
fun facadeMethod() {
a = A()
b = B()
c = C()
}
}
fun main(args: Array<String>) {
var facade = Facade()
facade.facadeMethod()
facade.a
}

例子中facadeMethod方法给出了一个一致的界面,实现了一个简单的外观模式。

代理模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
interface Proxy {
fun doSomething()
}
class ProxyIml : Proxy {
override fun doSomething() {
println("我是被代理的对象!")
}
}
class RealProxy(var proxy: Proxy = ProxyIml()) : Proxy {
override fun doSomething() {
println("我是代理人!")
proxy.doSomething()
}
}
fun main(args: Array<String>) {
RealProxy().doSomething()
}

这里暂时只给出静态代理,动态代理在本站关于AOP的部分中已经提到过。

参考

http://www.runoob.com

图解设计模式

Why when implementing clone method we return super.clone() not this clone()