设计模式-原型模式

70 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

模式意图

用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。

对象的创建如果比较复杂,就可以使用原型模式创建对象。

实现类的性能或安全要求比较高,可以让该类实现克隆接口,通过克隆获取对象而不是new。 

分类

浅克隆:克隆的新对象与原对象完全相同,对于非基本类型的属性,仍指向原对象的内存地址。

深克隆:克隆的新对象与原对象内存地址不同。

结构

  • 抽象原型类
  • 具体原型类:实现抽象原型类的clone方法
  • 访问类

浅克隆实现

实现了Cloneable接口的类并且重写clone方法就可以被克隆

class Realizetype implements Cloneable{
    private String name = "zz";

    private int age = 18;

    Realizetype(){
        System.out.println("原型对象创建完成");//只打印了一次,说明原型模式底层不是通过构造器实现
    }
    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public Realizetype clone() throws CloneNotSupportedException {
        return (Realizetype) super.clone();//返回原型类,原型的属性和方法都不变
    }
}

public class Client{
    public static void main(String[] args) throws CloneNotSupportedException {
        Realizetype r = new Realizetype();
        Realizetype cl;
        cl = r.clone();
        System.out.println(cl.getAge());//18
        System.out.println(cl.getName());//zz
        System.out.println(r==cl);//比较两个对象的地址值  false
    }
}

浅克隆案例

三好学生奖状,奖状除了名字不同,其他均相同

class Citation implements Cloneable{
    private String name;

    public String getName() {
        return name;
    }

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

    public void show(){
        System.out.println(name+"同学表现优异,特发此状!");
    }
    @Override
    public Citation clone() throws CloneNotSupportedException {
        return (Citation) super.clone();
    }
}

public class Client{
    public static void main(String[] args) throws CloneNotSupportedException {
        Citation citation = new Citation();
        Citation clone = citation.clone();
        citation.setName("张三");
        clone.setName("李四");
        citation.show();
        clone.show();
    }
}

深克隆

class Citation implements Cloneable{
    private Student student;

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

    public void show(){
        System.out.println(student.getName()+"同学表现优异,特发此状!");
    }
    @Override
    public Citation clone() throws CloneNotSupportedException {
        return (Citation) super.clone();
    }
}

public class Client{
    public static void main(String[] args) throws CloneNotSupportedException {
        Citation citation = new Citation();
        Student student = new Student();
        student.setName("张三");
        citation.setStudent(student);

        Citation clone = citation.clone();
        Student student1 = clone.getStudent();
        student1.setName("李四");

        citation.show();
        clone.show();
    }
}

class Student{
    private String name;

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                '}';
    }
}

浅克隆出现的问题

当克隆类中有一个student类时,复制出来的Citation中的student和原citation的student是同一个,所以两个citation执行show方法时,都会打印李四的名字。

深克隆需要使用对象流操作

把奖状对象写到文件中或序列化到硬盘上,再读取对象,获取到的对象就是完全不同的对象。

import java.io.*;

class Citation implements Cloneable, Serializable {
    private Student student;

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

    public void show(){
        System.out.println(student.getName()+"同学表现优异,特发此状!");
    }
    @Override
    public Citation clone() throws CloneNotSupportedException {
        return (Citation) super.clone();
    }
}

public class Client{
    public static void main(String[] args) throws Exception {
        Citation citation = new Citation();
        Student student = new Student();
        student.setName("张三");
        citation.setStudent(student);

        //创建对象输出流对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:a.txt"));
        //写对象
        oos.writeObject(citation);
        //释放资源
        oos.close();
        //创建对象输入流对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:a.txt"));
        //读取对象
        Citation clone = (Citation) ois.readObject();
        //释放资源
        ois.close();

        Student student1 = clone.getStudent();
        student1.setName("李四");
        citation.show();
        clone.show();
    }
}

class Student implements Serializable{
    private String name;

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                '}';
    }
}

​编辑

 Citation和Student类必须实现序列化接口