原型模式

原型模式

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

原型模式包含如下角色:

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

接口类图如下:

原型模式

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

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

原型模式指的就是浅克隆

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

实现代码:[原型模式代码](# 原型模式代码)

构造方法没有多次执行,说明底层不是通过new对象的方式克隆新对象的,

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

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

类图:

案例代码:[原型模式案例代码](# 原型模式案例代码)

浅克隆不是浅拷贝,在java里面的浅克隆还是创建了一个新对象

浅克隆的对象中八种基本数据类型都是独立存储的,但是内部的对象变量不会,因为java对象是引用

使用场景:

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

深克隆【扩展】

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

代码:[深克隆扩展案例代码1](# 深克隆扩展案例代码1)

说明stu对象和stu1对象是同一个对象,就会产生将stu1对象中name属性值改为“李四”,两个Citation(奖状)对象中显示的都是李四,这就是浅克隆的效果。

对具体原型类(Citation)中的引用类型的属性进行引用的复制。这种情况需要使用深克隆,而进行深克隆需要使用对象流。

代码:[深克隆扩展案例代码2](# 深克隆扩展案例代码2)

报错修改:NotSerializableException

因为把citation类的对象序列化到文件里,要求citation类必须实现序列化接口Serializablecitation类里面包含Student类,序列化citation时会把Student也序列化到文件中了,所以都需要实现序列化接口。

代码区

原型模式代码

具体原型类

package com.lmcode.PrototypeMode;

public class Realizetype implements Cloneable{
    public Realizetype(){
        System.out.println("构造方法执行");
    }
    protected Realizetype clone() throws CloneNotSupportedException {
        System.out.println("执行clone");
        return (Realizetype) super.clone();
    }
}

main

package com.lmcode.PrototypeMode;

public class main {
    public static void main(String[] args) throws CloneNotSupportedException {
        Realizetype realizetype = new Realizetype();
        Realizetype realizetype1 = realizetype.clone();
        System.out.println(realizetype == realizetype1);//构造方法执行,执行clone,false
    }
}

原型模式案例代码

package com.lmcode.PrototypeMode.case1;
//奖状类
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(name + "被评为三好学生。特发此状!");
    }

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

main

package com.lmcode.PrototypeMode.case1;

public class main {
    public static void main(String[] args) throws CloneNotSupportedException {
        Citation citation = new Citation();
        citation.setName("张三");
        Citation citation1 = citation.clone();
        citation1.setName("李四");
        citation.show();//张三被评为三好学生。特发此状!
        citation1.show();//李四被评为三好学生。特发此状!
    }
}

深克隆扩展案例代码1

学生类

package com.lmcode.PrototypeMode.deepCloneCase;

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;
    }
}

奖状类,具体原型类,实现了Cloneable接口里的clone()

package com.lmcode.PrototypeMode.deepCloneCase;

public 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();
    }
}

main

package com.lmcode.PrototypeMode.deepCloneCase;

public class main {
    public static void main(String[] args) throws CloneNotSupportedException {
        // 创建原型对象
        Citation citation = new Citation();
        Student student = new Student("张三","北京");
        citation.setStudent(student);

        // 克隆出一个新的原型对象
        Citation citation2 = citation.clone();

        Student student2 = citation2.getStudent();

        // 将克隆出来的原型对象citation2中的Student属性的name改为李四
        student2.setName("李四");
        System.out.println(student == student2);//true
        citation.show();//李四被评为三好学生。特发此状!
        citation2.show();//李四被评为三好学生。特发此状!
    }
}
//结果是都被改为李四了

深克隆扩展案例代码2

package com.lmcode.PrototypeMode.deepCloneCase2;

import java.io.Serializable;

public class Citation implements Cloneable, Serializable {
    private static final long serialVersionUID = 1L; // 可选,但推荐

    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();
    }
}
package com.lmcode.PrototypeMode.deepCloneCase2;

import java.io.Serializable;

public class Student implements Serializable {
    private static final long serialVersionUID = 1L; // 可选,但推荐

    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;
    }
}
package com.lmcode.PrototypeMode.deepCloneCase2;

import java.io.*;

public class main {
    public static void main(String[] args) throws Exception {
        Citation citation1 = new Citation();
        Student student1 = new Student("张三", "西安");
        citation1.setStudent(student1);

        // 创建对象输出流对象
        ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("D:\\lmcode\\IOFileAddress\\deepCloneCase.txt"));
        // 将citation1对象写入
        oos.writeObject(citation1);
        oos.close();

        // 创建对象输入流对象
        ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream("D:\\lmcode\\IOFileAddress\\deepCloneCase.txt"));
        Citation citation2 = (Citation) ois.readObject();
        Student student2 = citation2.getStudent();
        student2.setName("李四");

        System.out.println(student1 == student2);//false
        citation1.show();//张三被评为三好学生。特发此状!
        citation2.show();//李四被评为三好学生。特发此状!

    }
}
posted @ 2024-05-20 16:27  燕子去了  阅读(3)  评论(0编辑  收藏  举报

Powered by .NET 8.0 on Kubernetes

我会翻山越岭,到每一个我想去的地方

...