原型模式

原型模式

1.介绍

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

原型模式包含如下角色:

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

2.实现

原型模式的克隆分为浅克隆和深克隆。

  • 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原 有属性所指向的对象的内存地址
  • 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址

原型模式

浅克隆实现

Java中的Object类中提供了 clone() 方法来实现浅克隆。

Cloneable 接口是上面的类图中的抽 象原型类,

而实现了Cloneable接口的子实现类就是具体的原型类。

代码如下:

具体原型类

/**
 * @author
 * @date 2021/11/30 23:12
 * 具体的原型类
 */
@Data
public class Realizetype implements Cloneable {

    private Student student;

    public Realizetype() {
        System.out.println("具体原型类创建成功");
    }

    @Override
    protected Realizetype clone() throws CloneNotSupportedException {
        System.out.println("具体原型复制成功!");
        return (Realizetype) super.clone();
    }
}

访问类(测试)

/**
 * @author
 * @date 2021/11/30 23:14
 * 测试访问类
 */
public class PrototypeTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student = new Student("zhangsan",18);

        Realizetype r1 = new Realizetype();
        r1.setStudent(student);
        Realizetype r2 = r1.clone();

        System.out.println(r2==r1);//false
        System.out.println(r1.getStudent()== r2.getStudent());//true
    }
}

从打印结果来看,两个对象的成员属性student指向同一个地址,所以这种克隆方式属性浅克隆,

深克隆实现

序列化方式

注意:Realizetype和Student类都要实现Serializable接口

/**
 * @author
 * @date 2021/12/1 0:01
 * 序列化方式实现深克隆
 */
public class SerializePrototypeTest {
    public static void main(String[] args) throws Exception{
        Student student = new Student("zs",22);

        Realizetype r1 = new Realizetype();
        r1.setStudent(student);

        //将对象序列化 写入到磁盘
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\文件下载\\a.txt"));
        oos.writeObject(r1);
        oos.close();

        //反序列化  读取对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\文件下载\\a.txt"));
        Realizetype r2 = (Realizetype) ois.readObject();
        ois.close();

        System.out.println(r1==r2);
        System.out.println(r1.getStudent()==r2.getStudent());//false  没有指向同一个对象
    }
}

自定义clone方法实现

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Serializable,Cloneable {
    private String name;
    private Integer age;

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

重写clone方法

/**
 * @author
 * @date 2021/11/30 23:12
 * 具体的原型类
 */
@Data
public class Realizetype implements Cloneable , Serializable {

    private Student student;

    public Realizetype() {
        System.out.println("具体原型类创建成功");
    }

    /**
     * 自定义clone方法实现深克隆
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Realizetype clone() throws CloneNotSupportedException {
        //先对对象进行浅克隆
        Realizetype realizetype = (Realizetype) super.clone();

        //将成员属性设置成一个新的对象  把原来的值set进去
        //或者成员属性也重写重写clone方法  我们使用clone方法复制即可  但是如果很深的话就很烦(成员对象内部又有自己的非基本类型成员对象)
        Student student = realizetype.getStudent();//目前执行同一个地址
        Student newStu = student.clone();
        realizetype.setStudent(newStu);
        return realizetype;
    }
}

测试

/**
 * @author
 * @date 2021/11/30 23:14
 * 测试访问类
 */
public class PrototypeTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student = new Student("zhangsan",18);

        Realizetype r1 = new Realizetype();
        r1.setStudent(student);
        Realizetype r2 = r1.clone();

        System.out.println(r2==r1);//false
        System.out.println(r1.getStudent()== r2.getStudent());//false
    }
}

观察测试结果 发现实现了深拷贝

3.使用场景

  • 对象的创建非常复杂,可以使用原型模式快捷的创建对象。

  • 新对象和就对象的大部分属性都一样

  • 性能和安全要求比较高。(无需新建对象再去一个一个set属性,clone是native方法,性能高)

上一篇:蓝桥杯-乘积最大


下一篇:JavaScript 原型对象(用一个例子讲清楚,三岁小表弟都听懂了)