原型模式-java

概念:

原型模式:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。

实现方式:

抽象原型类:规定了具体原型对象必须实现的clone()方法
具体原型类:实现抽象原型类的clone()方法,它是可被复制的对象
访问类:使用具体原型类的clone()方法来复制新的对象

原型模式分为浅克隆、深克隆

实现1:(浅克隆)

java中object类中提供了clone()方法来实现浅克隆, Cloneable接口就是抽象原型类,实现了Cloneable接口的子类就是具体的原型类。如下:

public class Phone implements Cloneable {
    private String name;
    public Phone() {
        System.out.println("调用构造方法创建对象");
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    protected Phone clone() throws CloneNotSupportedException {
        System.out.println("调用克隆方法创建对象");
        return (Phone) super.clone();
    }
}
public class Test {
    public static void main(String[] args) {
        try {
            Phone phone1 = new Phone();
            phone1.setName("小米手机");
            Phone phone2 = phone1.clone();
            System.out.println("phone1: "+phone1.getName()+"\nphone2: "+phone2.getName());
            phone2.setName("华为手机");
            System.out.println("phone1: "+phone1.getName()+"\nphone2: "+phone2.getName());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}
输出结果:
image.png

从输入结果可以看出,当调用原型类clone方法时,并没有再次调用构造方法。对象的属性也会一同被复制。

实现2:(深克隆)

还是以生产手机为例,这次我们在手机里添加一个CPU类引用。

public class Phone implements Cloneable, Serializable {
    private String name;
    private Cpu cpu;

    public String getName() {
        return name;
    }

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

    public Cpu getCpu() {
        return cpu;
    }

    public void setCpu(Cpu cpu) {
        this.cpu = cpu;
    }

    @Override
    protected Phone clone() throws CloneNotSupportedException {
        return (Phone) super.clone();
    }

    @Override
    public String toString() {
        return name + " : cpu name:" + cpu.getName() + " version:" + cpu.getVersion();
    }
}
public class Cpu implements Serializable {
    private String name;
    private String version;

    public String getName() {
        return name;
    }

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

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }
}
public class Test {
    public static void main(String[] args) {
        //一 浅克隆 引用对象指向原来的地址,修改属性值,都会一起修改
        try {
            Phone phone = new Phone();
            phone.setName("小米手机");
            Cpu cpu = new Cpu();
            cpu.setName("骁龙");
            cpu.setVersion("850");
            phone.setCpu(cpu);
            Phone phone2 = phone.clone();
            phone2.getCpu().setVersion("888");
            System.out.println(phone.toString());
            System.out.println(phone2.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("===============");
        //二 深克隆 通过序列化对象方式
        try {
            Phone phone = new Phone();
            phone.setName("华为手机");
            Cpu cpu = new Cpu();
            cpu.setName("麒麟");
            cpu.setVersion("900");
            phone.setCpu(cpu);

            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("***/b.txt"));
            oos.writeObject(phone);
            oos.close();

            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("***/b.txt"));
            Phone phone2 = (Phone) ois.readObject();
            ois.close();

            phone2.getCpu().setVersion("990");
            System.out.println(phone.toString());
            System.out.println(phone2.toString());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
输出结果:

image.png

由该示例可以得出:
浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。(注意String虽然是引用类型,但和其他引用类型的区别在于,原先的string的值一旦创建后,就不会改变使用+/-操作,原先的字符串还是在内存中,+/-完的字符串会写入新分配的内存中,而不会改变原有的堆上的数据。
深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
优点: 1、性能提高。 2、逃避构造函数的约束。
缺点: 1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、必须实现 Cloneable 接口。

你可能感兴趣的:(原型模式-java)