原型模式(创建者)

原型模式(浅克隆与深克隆)

概述

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

结构

原型模式包括如下角色:

抽象原型类:规定了具体原型对象必须实现的的clone ()方法。

具体原型类:实现抽象原型类的clone ()方法,它是可被复制的对象。

访问类:使用具体原型类中的clone ()方法来复制新的对象。

接口类图如下:

在这里插入图片描述

实现

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

浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。

深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

浅克隆和深克隆区别
浅克隆: 被Clone的对象的所有变量都含有原来对象相同的值,而引用变量还是原来对用的引用【拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。】
深克隆: 被克隆对象的所有变量都含有原来的对象相同的值,引用变量也重新复制了一份【不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象】

Java中的object类中提供了clone(坊法来实现浅克隆。Cloneable接口是上面的类图中的抽象原型类,而实现了cloneable接口的子实现类就是具体的原型类。代码如下:

Realizetype(具体的原型类):

//原型类:
package com.igeek.pattern.protyte.demo;

public class Realizetype implements Cloneable{
    public Realizetype() {
        System.out.println("具体的原型对象创建完成");
    }

    @Override
    public Realizetype clone() throws CloneNotSupportedException {
        System.out.println("具体原型复制成功!");
        return (Realizetype) super.clone();
    }
}
//测试类:
package com.igeek.pattern.protyte.demo;

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        Realizetype realizetype=new Realizetype();
        Realizetype clone = realizetype.clone();
        System.out.println("创建的对象是否与克隆的对象是同一个:"+(realizetype==clone));
    }
}

案例

用原型模式生成"三好学生"奖状

同一学校的"三好学生"奖状除了获奖人姓名不同,其他都相同,可以使用原型模式复制多个"三好学生"奖状出来,然后在修改奖状上的名字即可。

类图如下:

在这里插入图片描述

代码如下:

//奖状类
package com.igeek.pattern.protyte.demo1;

public class Cation implements Cloneable{
    //三号学生姓名
    private String name;
    public Cation() {
    }

    public String getName(){
        return name;
    }
    public void setName(String name){
        this.name=name;
    }
    public Cation clone() throws CloneNotSupportedException {
        return (Cation) super.clone();
    }
    public void show(){
        System.out.println(name+"同学:在2022学年第一学期中表现优秀,都被评为三好学生。特发此奖状");
    }
}
//测试类:
package com.igeek.pattern.protyte.demo1;

public class CationTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Cation cation=new Cation();
        Cation clone = cation.clone();
        cation.setName("杨明");
        clone.setName("成林");
        cation.show();
        clone.show();
    }
}

使用场景4

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

性能和安全要求比较高。

扩展(深克隆)

将上面的三好学生的案列中Citation类的name属性修改为Student类型的属性,代码如下:

//Student类:
package com.igeek.pattern.protyte.demp2;

import java.io.Serializable;

public 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
package com.igeek.pattern.protyte.demp2;

import java.io.Serializable;

public class Citation implements Cloneable, Serializable {
    private Student stu;

    public Student getStu(){
        return stu;
    }

    public void setStu(Student stu){
        this.stu=stu;
    }

    public Citation clone() throws CloneNotSupportedException {
        return (Citation) super.clone();
    }

    public void show(){
        System.out.println(stu.getName()+"同学:在2022学年第一学期中表现优秀,都被评为三好学生。特发此状!");
    }
}
//测试类:
package com.igeek.pattern.protyte.demp2;

import java.io.*;

public class CitaionTest {
    public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
        //1.创建原型对象
        Citation citation=new Citation();
        //创建张三学生对象
        Student stu=new Student();
        stu.setName("张三");
        citation.setStu(stu);

        //创建对象输出流对象
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("a.txt"));
        //写对象
        oos.writeObject(citation);
        //释放资源
        oos.close();
        //创建对象输入流对象
        ObjectInputStream ios=new ObjectInputStream(new FileInputStream("a.txt"));
        //读取对象
        Citation citation1= (Citation) ios.readObject();
        //释放资源
        ios.close();
         Student stu1=citation1.getStu();
         stu1.setName("李四");
         citation.show();
         citation1.show();
    }
}

如果是浅克隆,那么浅克隆的类中存在其他的引用数据类型,是无法被克隆的,指向的还是原来的那个对象,不会改变。改变的仅仅是克隆对象的地址与原地址不同。(内部含有其他对象属性)

如果输出结果的话,就全部是李四同学了。

深克隆运行结果:

在这里插入图片描述

注意:Citation类和Student类必须实现Serializable接口,否则会抛NotSerializableException异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值