[设计模式](四):建造者模式(Builder)与原型模式(Prototype)[含Kotlin深克隆实例代码]

来源:互联网 发布:国外注册域名 备案 编辑:程序博客网 时间:2024/06/05 10:35

    建造者模式(Builder)与原型模式(Prototype)都是一种创建型模式

>建造者模式(Builder)

    建造者模式与工厂模式中的抽象工厂有点类似,都是关心组产品的组合问题。而其区别之处在于,建造者模式关注的是最终产品的构建即组装过程(组原料->产品),工厂模式关注的是产品的构建即创建过程(组产品工厂->生产组产品)。举个小例子:

class House{//kotlin代码    lateinit  var door:String    lateinit  var window:String    lateinit  var wall:String}interface HouserBuilderInterface{    fun setDoor()    fun setWindow()    fun setWall()    fun build():House}class BigHouseBuilder:HouseBuilderInterface{    private var house:House = House()    override fun setDoor(){        house.door="铁门"    }    override fun setWindow(){        house.window="豪华窗户"    }    override fun setWall(){        house.wall="豪华墙壁"    }    override fun build():House{        setDoor()        setWall()        setWindow()        return house    }}
    当我需要建造一个贫民窟时,只需要写一个PoorBuilder实现HouseBuilderInterface,就可以了,无需修改或记忆原有的复杂构建方法,符合OCP(开闭原则)。

    建造者模式的优点是:

  • 封闭了内部构建细节,符合DP原则;
  • 对扩展开放,对修改封闭;
  • 能稳定地构建复杂的对象。

>原型模式(Prototype)

    原型模式是指,将某个类当成一个原型,利用克隆、复制等方法快速的构建这个对象。举个例子,孙悟空拔一撮毛,吹毛成分身,这些分身就是原型对象。

    对于JVM,直接实现Cloneable接口中的clone方法即可。由于Cloneable接口中的clone默认为protected的,有时候需要将其改写为public方便调用。

    另外,对于克隆,分为浅克隆和深克隆:

  • 前者克隆是不完全的,不会克隆引用,这是由于clone中使用的是 = 操作符造成的(JAVA中 = 操作符对对象赋值做引用操作);
  • 后者克隆是完全的。
    怎么理解呢?看下面这段Kotlin示例代码:

class Prototype:Cloneable{//实现克隆接口    var a = 7 //这是一个属性    var h=BigHouseBuilder().build() //这是一个对象引用,具体代码见上    //重写克隆方法,默认浅克隆    public override fun clone(): Any {        return super.clone()    }}fun main(arg:Array<String>){    val p=Prototype()    println(p.a) // 输出 7    println(p.h.wall) // 输出"豪华墙壁"    val p2=p.clone()//由p克隆一个p2    p.a++ // 改变原型中的值     p.h.wall="这是原对象的墙" //改变原型中引用对象的属性值    if (p2 is Prototype) {        println(p2.a) // 输出 7 ,克隆成功        println(p2.h.wall)// 输出原型对象中对House的引用对象的wall值,输出"这是原对象的墙" ,克隆失败    }}
    那么要怎么做到深克隆呢?答:手动对对象引用进行一个new操作:(把上面代码中的clone方法重写成下面这个样子)

    public override fun clone(): Any {        val c=super.clone()        if (c is Prototype)c.h = BigHouseBuilder().build()//手动new一个对象引用出来        return c    }

    然而,这样并不算完全的深克隆,因为如果此时House对象的值是变化过的,我这里只是build出来一个新的,仍然是默认值,显然不符合要求因此,可以考虑用序列化和反序列化的方法进行克隆:

    public fun deepClone(): Any{        val bos = ByteArrayOutputStream()        val oos = ObjectOutputStream(bos)        oos.writeObject(this)//写出序列化后的对象        val bis = ByteArrayInputStream(bos.toByteArray())        val ois = ObjectInputStream(bis)        return ois.readObject()//读入反序列化后的对象,并返回    }
    此时要记得,对Prototype和House都要进行序列化:

class House:Serializable{     val ID:Long = 1L}class Prototype:Cloneable,Serializable{         val ID:Long = 1L }


    另外,为什么用clone而不是copy?经过测试,clone方法比copy方法的开销是copy的一半,但当原型中对象引用过多且做了深克隆时,clone的开销接近copy方法。

    那么原型模式究竟有什么用呢?比如,做游戏设计时,做分身技能,用于快速地复制一些Monster;或是面对几个对象间差别不大,只有略微几个属性值不同时,单独构建一个工厂或是Builder显然冗余,此时用原型直接克隆出来稍微改改就非常合适。


>>[设计模式]OOP设计模式·目录


阅读全文
1 0
原创粉丝点击