Java 23种设计模式(3.创建者模式-原型模式)

文章介绍了Java中的原型模式,包括其结构、实现方式,通过代码示例展示了浅克隆和深克隆的区别,并提供了具体原型类和抽象原型类的实现。此外,文章还讨论了原型模式的使用场景,如复杂对象的快速创建,并给出了深克隆的实现方法,包括使用`clone()`方法和对象流实现深拷贝。

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

1.概述

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

2.结构

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

3.实现-类图

在这里插入图片描述
原型模式的克隆分为浅克隆深克隆
关于深浅克隆参考之前我写的文章

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

4. 代码

public class RealizeType implements Cloneable{
    public RealizeType(){
        System.out.println("it's original");
    }

    public RealizeType clone() throws CloneNotSupportedException{
        System.out.println("it's clone");
        return (RealizeType) super.clone();
    }
}

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        RealizeType realizeType = new RealizeType();//创建一个原型类对象
        RealizeType clone = realizeType.clone(); //调用Realizetype类中的clone方法进行对象的克隆
        System.out.println(realizeType==clone);//原型对象和克隆出来的是否是同一个对象
        System.out.println(realizeType.equals(clone));//原型对象和克隆出来的值是否相等
        System.out.println(realizeType.getClass()==realizeType.getClass());//原型对象和克隆出来的是否是同一个class
    }
}

运行结果:

it's original
it's clone
false
false
true

5. 案例

三好学生的奖状除了姓名不同,其他都相同

5.1 类图

5.2 代码

public class Citation implements Cloneable{
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Citation clone() throws CloneNotSupportedException{
        return (Citation) super.clone();
    }
    public void show(){
        System.out.println(getName() + "同学:在2023学年第一学期中表现优秀,被评为三好学生。特发此状!");
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Citation original = new Citation();
        original.setName("aaaa");
        Citation clone = original.clone();//复制奖状
        clone.setName("bbbb");//将奖状的名字修改
        original.show();
        clone.show();
    }
}


5.3 运行结果

aaaa同学:在2023学年第一学期中表现优秀,被评为三好学生。特发此状!
bbbb同学:在2023学年第一学期中表现优秀,被评为三好学生。特发此状!

6. 使用场景

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

7. 扩展(深克隆)

浅克隆

public class Student {
    private String name;
    private String address;

    public Student(String name,String address) {//构造方法
        this.name = name;
        this.address = address;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
    
    public String getName() {
        return name;
    }

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

public class Citation implements Cloneable{
    private Student student;

    public void setStudent(Student student){
        this.student = student;
    }
    public Student getStudent(){
        return student;
    }
    public Citation clone() throws CloneNotSupportedException{
        return (Citation) super.clone();
    }
    public void show(){
        System.out.println(student.getName() + "同学:在2023学年第一学期中表现优秀,被评为三好学生。特发此状!");
    }
}

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Citation original = new Citation();
        Student student1 = new Student("aaaa","Shanghai");
        original.setStudent(student1);

        Citation clone = original.clone();//复制奖状
        clone.getStudent().setName("bbbb");//获取clone奖状并修改对象的名字  false

        System.out.println(original==clone);//原型对象和克隆出来的是否是同一个对象 false
        System.out.println(original.equals(clone));//原型对象和克隆出来的值是否相等 true
        System.out.println(original.getClass()==clone.getClass());//原型对象和克隆出来的是否是同一个class
        original.show();
        clone.show();
    }
}

运行结果:

false
false
true
bbbb同学:在2023学年第一学期中表现优秀,被评为三好学生。特发此状!
bbbb同学:在2023学年第一学期中表现优秀,被评为三好学生。特发此状!

在这里插入图片描述

深克隆

以上的代码让clone后的student的name改变,需要满足以下规则
深度克隆需要满足以下规则:

  1. 无需单独复制元数据。
  2. 原始类中的所有成员类都应支持克隆,并且上下文中原始类的克隆方法应在所有成员类上调用 super.clone() 。
  3. 如果某个成员类不支持克隆,那么在clone方法中,必须创建一个该成员类的新实例,并将其所有属性复制到新的成员类对象中。这个新的成员类对象将被设置在克隆对象中。
public class Student implements Cloneable {
    private String name;
    private String address;

    protected Object clone() throws CloneNotSupportedException{//添加了clone
        return super.clone();
    }
    public Student(String name,String address) {//构造方法
        this.name = name;
        this.address = address;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getName() {
        return name;
    }

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

public class Citation implements Cloneable{
    private Student student;

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

//    public Citation clone() throws CloneNotSupportedException{
//        return (Citation) super.clone();
//    }
//以上是浅拷贝的方法,以下是深拷贝的方法
    public Citation clone() throws CloneNotSupportedException{
        Citation cloned = (Citation) super.clone();
        cloned.setStudent((Student)cloned.getStudent().clone());//让对象也clone的范围内
        return cloned;
    }
    public void show(){
        System.out.println(student.getName() + "同学:在2023学年第一学期中表现优秀,被评为三好学生。特发此状!");
    }
}

false
false
true
aaaa同学:在2023学年第一学期中表现优秀,被评为三好学生。特发此状!
bbbb同学:在2023学年第一学期中表现优秀,被评为三好学生。特发此状!

在这里插入图片描述

也可以使用对象流来实现深拷贝
🔔注意:Citation类和Student类必须实现Serializable接口,否则会抛NotSerializableException异常。

public class Student implements Serializable {
    private String name;
    private String address;
    public Student(String name,String address) {//构造方法
        this.name = name;
        this.address = address;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getName() {
        return name;
    }

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

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

    public void setStudent(Student student){
        this.student = student;
    }
    public Student getStudent(){
        return student;
    }
    public Citation clone() throws CloneNotSupportedException{
        return (Citation) super.clone();
    }
    public void show(){
        System.out.println(student.getName() + "同学:在2023学年第一学期中表现优秀,被评为三好学生。特发此状!");
    }
}

public class Test {
    public static void main(String[] args) throws Exception {
        Citation original = new Citation();
        Student student1 = new Student("aaaa","Shanghai");
        original.setStudent(student1);


        //创建对象输出流对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\testcode\\a.txt"));//使用序列化方式,前提是实现序列化接口将输出流对象存储再指定位置,
        //将original对象写出到文件中
        oos.writeObject(original);
        oos.close();
        //创建对象出入流对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\testcode\\a.txt"));
        //读取对象
        Citation clone = (Citation) ois.readObject();
        clone.getStudent().setName("bbbb");//获取clone奖状并修改对象的名字

        System.out.println(original==clone);//原型对象和克隆出来的是否是同一个对象
        System.out.println(original.equals(clone));//原型对象和克隆出来的值是否相等
        System.out.println(original.getClass()==clone.getClass());//原型对象和克隆出来的是否是同一个class
        original.show();
        clone.show();
    }
}
false
false
true
aaaa同学:在2023学年第一学期中表现优秀,被评为三好学生。特发此状!
bbbb同学:在2023学年第一学期中表现优秀,被评为三好学生。特发此状!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值