场景

  • 思考一下:克隆技术是怎样的过程?克隆羊多莉大家还记得吗?

  • javascrip语言中,继承怎么实现?那里面也有prototype,大家还记得吗?

原型模式

  • 通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式

  • 就是java中的克隆技术,以某个对象为原型,复制出新的对象.显然,

  • 优势有:效率高(直接克隆,避免了重新执行构造过程步骤)

  • 克隆类似于new,但是不同于new.new创建新的对象属性采用的是默认值.克隆出的对象的属性值完全和原型对象相同.并且克隆出的新对象改变不会影响原型对象.然后再修改克隆对象的值

原型模式实现

  • Cloneable接口可clone方法

  • Protype模式中实现起来最困难的地方就是内存复制操作,所幸Java中提供了clone()方法替我们做了绝大部分事情

import java.util.Date;

//1997年英国克隆羊多莉
public class Sheep implements Cloneable{
    private  String name;
    private Date brithday;

    public Sheep() {
        // TODO Auto-generated constructor stub
    }

    public Sheep(String name, Date brithday) {
        super();
        this.name = name;
        this.brithday = brithday;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Date getBrithday() {
        return brithday;
    }

    public void setBrithday(Date brithday) {
        this.brithday = brithday;
    }

    //重写Object的clone方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
import java.util.Date;

public class Client {

    @SuppressWarnings("deprecation")
    public static void main(String[] args) throws CloneNotSupportedException {
        //浅克隆
        Date d = new Date(183964743);
        Sheep s1 = new Sheep("莉莉",d);
        System.out.println(s1);
        System.out.println(s1.getName());
        System.out.println(d.getTime());
        d.setDate(183974743);
        System.out.println(d.getTime());

        Sheep s2 = (Sheep) s1.clone();
        System.out.println(s2);
        System.out.println(s2.getName());
        s2.setName("多莉");
        System.out.println(s2.getName());
        System.out.println(d.getTime());

    }

}
import java.util.Date;

//1997年英国克隆羊多莉
public class Sheep implements Cloneable{
    private  String name;
    private Date brithday;

    public Sheep() {
        // TODO Auto-generated constructor stub
    }

    public Sheep(String name, Date brithday) {
        super();
        this.name = name;
        this.brithday = brithday;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Date getBrithday() {
        return brithday;
    }

    public void setBrithday(Date brithday) {
        this.brithday = brithday;
    }

    //重写Object的clone方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object obj = super.clone();
        //添加如下代码实现深复制
        Sheep s = (Sheep)obj;
        //把属性也进行克隆
        s.brithday = (Date)this.brithday.clone();
        return obj;
    }
}
import java.util.Date;

/**
 * 深复制
 * @author Matrix42
 *
 */
public class Client2 {
    public static void main(String[] args) throws CloneNotSupportedException {
        Date d = new Date(183964743);
        Sheep s1 = new Sheep("莉莉",d);
        System.out.println(s1);
        System.out.println(s1.getName());
        System.out.println(s1.getBrithday());

         Sheep s2 = (Sheep) s1.clone();

        d.setTime(2222222222222L);
        System.out.println(s1.getBrithday());

        System.out.println(s2.getBrithday());
    }
}

利用序列化和反序列化技术实现深克隆

短时间大量修改对象时,原型模式和普通new方式效率测试

  • 创建对象比较耗时时大约提高1000倍左右

开发中的应用场景

  • 原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone方法创建一个对象,然后由工厂方法提供给调用者

    • spring中的bean的创建市级就是两种:单例模式和原型模式(原型模式需要和工厂模式搭配起来)

Sheep实现Serializable接口

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;

/**
 * 使用序列化和反序列化实现深克隆
 * @author Matrix42
 *
 */
public class Client3 {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Date d = new Date(183964743);
        Sheep s1 = new Sheep("莉莉",d);
        System.out.println(s1);
        System.out.println(s1.getName());
        System.out.println(s1.getBrithday());

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);

        oos.writeObject(s1);
        byte[] bytes = bos.toByteArray();

        ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
        ObjectInputStream ois = new ObjectInputStream(bis);

        Sheep s2 = (Sheep) ois.readObject();

        System.out.println(s2.getName());

    }

}