原型模式

  原型模式的定义简单的来讲就是通过一个对象能够生成很多个相同(类型,成员变量的值,方法等)又不同(内存地址)的对象。在实际开发中,有些类的创建过程比较复杂,而这个类我们又需要频繁的用到。这个时候使用new方法来创建就比较麻烦,而使用原型模式可以帮我们很快的生成很多的对象,而不用再去一步步的生成新的对象。

  原型模式的实现方式比较简单,一个clone方法的接口,然后目标类实现这个接口就好了,因为java所有的类都继承自Object类,而Object类又是提供了clone()方法的实现的,因此我们直接使用Object类的clone方法就好了,不过需要注意的是使用Object类的clone方法需要实现Cloneable接口。不然会抛异常。

/**
 * created by xushilong on 2018/10/22.
 */
public class B {
    private String b;

    public String getB() {
        return this.b;
    }

    public void setB(String b) {
        this.b = b;
    }
}
/**
 * created by xushilong on 2018/10/22.
 */
public class A implements Cloneable{
    private B b;

    public A clone() {
        try {
            return (A) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }

    public B getB() {
        return this.b;
    }

    public void setB(B b) {
        this.b = b;
    }
}
 public static void main(String[] args) {
        A a=new A();
        B b=new B();
        b.setB("xsl");
        a.setB(b);
        A newA=a.clone();
        System.out.println(a.hashCode() == newA.hashCode());
        System.out.println(a.getB().getB().equals(newA.getB().getB()));
        System.out.println(a.getB().hashCode() == newA.getB().hashCode());
        a.getB().setB("test");
        System.out.println(newA.getB().getB());
    }

  从代码中可以看出A只需要实现cloneable接口就可以很快的不断的复制自己了。但是测试发现a和newA的b属性仍然属于同一个对象,而且更改a的B对象的b属性发现newA的B对象的b属性也更改了。这里就涉及到Java的深拷贝和浅拷贝了。

  这里就简短的讲述两者的区别,想深入了解的可以自行搜索。首先java是分为基本数据类型和引用类型的。基本数据类型在做参数传递时是通过值传递,而引用类型是通过引用传递,所以如果一个类中如果有引用对象的话,那么克隆出来的对象的引用对象和原本的对象的引用对象其实是指向同一个内存地址的(也就是说克隆出来的对象的引用对象和原先对象的引用对象实际上还是同一个对象),这就是浅拷贝,深拷贝就是克隆出来的对象的引用对象和原本的对象的引用对象不能是同一个对象。

  从测试代码中可以知道Object类的clone方法属于浅拷贝。那如果业务需要我们的clone方法需要使用深拷贝怎么办?简单,我们自己去实现clone方法,不使用Object类的clone方法就好了。我们可以通过序列化将一个对象存到流里面,然后再从流里面取出来来实现对象的深拷贝。

public A deepClone() throws IOException,ClassNotFoundException{
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);

        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return (A) ois.readObject();
    }

为了实现深拷贝,所有需要复制的对象都要实现序列化接口。比如这里不止A需要,B也需要,不然会报错。而且要注意对象的引用对象都需要是可以被序列化的。如果是不可被序列化的对象,可以将之设为transient。

posted @ 2018-10-22 21:25  徐世龙  阅读(111)  评论(0)    收藏  举报