创建型模式之原型模式

本文详细介绍了Java中的原型模式,包括原型类、具体原型类和访问类的角色,浅克隆和深克隆的区别,并通过实例演示如何创建和使用‘三好学生’奖状和深克隆优化。理解浅克隆与深克隆在对象复制中的作用,有助于提升代码复用和性能优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

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

结构

原型模式包含如下角色:

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

接口类图如下:

实现

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

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

Java中的Object类中提供了 `clone()` 方法来实现浅克隆。 Cloneable 接口是上面的类图中的抽象原型类,而实现了Cloneable接口的子实现类就是具体的原型类。

代码如下:

/**
 * @author: xuzhilei
 * @create: 2021-12-28
 * @description: 具体的原型类
 **/
public class Realizetype implements Cloneable{
    /**
     * 构造器
     */
    public Realizetype(){
        System.out.println("具体的原型对象创建完成!");
    }
    /**
     * 重写clone方法
     * @return Realizetype:具体的原型类实例
     * @throws CloneNotSupportedException
     */
    @Override
    protected Realizetype clone() throws CloneNotSupportedException {
        System.out.println("具体原型复制成功!");
        return (Realizetype) super.clone();
    }
}
/**
 * @author: xuzhilei
 * @create: 2021-12-28
 * @description: 测试访问类
 **/
public class PrototypeTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        //创建一个具体的原型类实例
        Realizetype realizetype1 = new Realizetype();
        //克隆出一个具体的原型类实例,会产生一个新的对象
        Realizetype realizetype2 = realizetype1.clone();
        System.out.println("realizetype1和realizetype2是同一个对象吗?"+(realizetype1 == realizetype2));
    }
}

测试结果:

 案例

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

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

类图如下:

代码如下:

public 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(this.name+"同学:在2020学年第一学期中表现优秀,被评为三好学生。特发此状!");
    }

    /**
     * 重写clone方法
     * @return Citation:具体的奖状类实例
     * @throws CloneNotSupportedException
     */
    @Override
    protected Citation clone() throws CloneNotSupportedException {
        return (Citation) super.clone();
    }
}
public class CitationTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        //创建奖状对象
        Citation citation1 = new Citation();
        citation1.setName("张三");

        //克隆奖状对象,会产生一个新的对象
        Citation citation2 = citation1.clone();
        citation2.setName("李四");

        citation1.show();
        citation2.show();
    }
}

测试结果:说明浅克隆生成了新对象

 使用场景

* 对象的创建非常复杂,可以使用原型模式快捷的创建对象。
* 性能和安全要求比较高。

浅克隆案例:将上面的“三好学生”奖状的案例中Citation类的name属性修改为Student类型的属性。

代码如下:

public class Citation implements Cloneable{
    private Student student;

    public Citation() {
    }

    public Citation(Student student) {
        this.student = student;
    }

    public Student getStudent() {
        return student;
    }

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

    public void show(){
        System.out.println(this.student.getName()+"同学:在2020学年第一学期中表现优秀,被评为三好学生。特发此状!");
    }

    /**
     * 重写clone方法
     * @return Citation:具体的奖状类实例
     * @throws CloneNotSupportedException
     */
    @Override
    protected Citation clone() throws CloneNotSupportedException {
        return (Citation) super.clone();
    }
}
public class Student {
    private String name;
    private String address;

    public Student(String name, String address) {
        this.name = name;
        this.address = address;
    }

    public Student() {
    }

    public String getName() {
        return name;
    }

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

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}
public class CitationTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        //创建奖状对象
        Citation citation1 = new Citation();
        Student student1 = new Student("张三", "北京");
        citation1.setStudent(student1);
        //克隆奖状对象,会产生一个新的奖状对象,但其内部的student2变量与student1变量指向同一个地址值
        Citation citation2 = citation1.clone();
        Student student2 = citation2.getStudent();
        student2.setName("李四");

        //判断student1对象和student2对象是否是同一个对象
        System.out.println("student1和student2是同一个对象?" + (student1 == student2));

        citation1.show();
        citation2.show();
    }
}

测试结果:

 分析:student1对象和student2对象是同一个对象,就会产生将student1对象中name属性值改为“李四”,两个Citation(奖状)对象中显示的都是李四。这就是浅克隆的效果,对具体原型类(Citation)中的引用类型的属性进行引用地址值的复制。这种情况需要使用深克隆,而进行深克隆需要使用对象流。

代码如下:

/**
 * @author: xuzhilei
 * @create: 2021-12-28
 * @description: 测试利用序列化实现深克隆
 **/
public class CitationTest04 {
    public static void main(String[] args) {

        ObjectOutputStream oos = null;
        ObjectInputStream ois = null;
        try {
            //创建奖状对象
            Citation citation1 = new Citation();
            Student student1 = new Student("张三", "上海");
            citation1.setStudent(student1);

            //创建输出流
            oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\DP\\Desktop\\a.text"));
            //将对象序列化到文件中
            oos.writeObject(citation1);

            //创建输入流
            ois = new ObjectInputStream(new FileInputStream("C:\\Users\\DP\\Desktop\\a.text"));
            //将文件反序列化成对象
            Citation citation2 = (Citation) ois.readObject();
            //获取citation2的学生对象
            Student student2 = citation2.getStudent();
            student2.setName("李四");

            //判断student1对象和student2对象是否是同一个对象
            System.out.println("student1和student2是同一个对象?" + (student1 == student2));

            citation1.show();
            citation2.show();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            try {
                if (oos != null){
                    oos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (ois != null){
                    ois.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

测试结果:说明student1对象和student2对象不是同一个对象

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

   以上是个人随手敲的demo,如有不正确的地方,可以在下方留言指正,谢谢。与各位优快云的伙伴们共勉,每天记录一点点,每天进步一点点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值