• 设计模式——原型模式


    定义:

    原型模式是一种创建型设计模式,它允许一个对象创建另一个可定制的对象,而无需了解如何创建这个对象的细节。这种模式的核心在于对象拷贝,即通过将一个原型对象传给要创建的对象,然后由这个要创建的对象通过请求原型对象拷贝自身来实施创建。

    本期代码:小麻雀icknn/设计模式练习 - Gitee.com

    Java中Object类是所有类的根类,Object 类提供了一个clone()方法,该方法可以将一一个Java对象复制一份,但是需要实现clone的Java类必须要实现一个接口Cloneable,该接口表示该类能够复制且具有复制的能力

    工作原理:

    通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对像拷贝它们自己来实现创建,即对象的clone()

    原型模式组成

    • 抽象原型类(CloneSource):定义了一个抽象的克隆方法。
    • 具体原型类(CloneTest1&CloneTest2):实现抽象原型类(接口)定义的克隆方法,提供一个具体的克隆方法来复制自己。
    • 客户端(PrototypeMain):使用原型类的对象来实现具体的操作,即通过复制原型对象来创建新的对象。

     例子:

    克隆源

    1. package com.study.main.Prototype;
    2. public class CloneSource implements Cloneable{
    3. public String getName() {
    4. return "克隆源";
    5. }
    6. @Override
    7. protected Object clone() throws CloneNotSupportedException {
    8. CloneSource cloneSource = null;
    9. try{
    10. cloneSource = (CloneSource) super.clone();
    11. }
    12. catch (CloneNotSupportedException err){
    13. err.printStackTrace();
    14. }
    15. return cloneSource;
    16. }
    17. }

     克隆1类

    1. package com.study.main.Prototype;
    2. public class CloneTest1 extends CloneSource{
    3. public void show(){
    4. System.out.println("测试克隆1");
    5. }
    6. }

     克隆2类 

    1. package com.study.main.Prototype;
    2. public class CloneTest2 extends CloneSource{
    3. public void show(){
    4. System.out.println("测试克隆2");
    5. }
    6. }

    实现类

    目标:克隆出2个克隆1类,2个克隆类

    1. package com.study.main.Prototype;
    2. public class PrototypeMain {
    3. public static void main(String[] args) throws CloneNotSupportedException {
    4. CloneTest1 cloneSource = new CloneTest1();
    5. CloneTest2 cloneSource2 = new CloneTest2();
    6. for (int i = 0; i < 2; i++) {
    7. CloneTest1 cloneTest= (CloneTest1) cloneSource.clone();
    8. cloneTest.show();
    9. System.out.println(cloneTest.getName());
    10. }
    11. for (int i = 0; i < 2; i++) {
    12. CloneTest2 cloneTest2= (CloneTest2) cloneSource2.clone();
    13. cloneTest2.show();
    14. System.out.println(cloneTest2.getName());
    15. }
    16. }
    17. }

     结果:

    注意 :

    • 实现 cloneable 接口: cloneable 接口与序列化接口的作用类似,它只是告诉虚拟机可以安全地在实现了这个接口的类上使用 clone() 方法。在 JVM 中,只有实现了Cloneable 接口的类才可以被拷贝,否则会抛出 CloneNotSupportedException 异常
    • 重写 object 类中的 clonel() 方法: 在 Java 中,所有类的父类都是 object 类,而 object类中有一个 clone)方法,作用是返回对象的一个拷贝。
    • 在重写的 clone() 方法中调用 super.clone(): 默认情况下,类不具备复制对象的能力,需要调用 super.clone() 来实现 

    深拷贝&浅拷贝

    浅拷贝

    浅贝 是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。

    例子:

    学生类:

    1. package com.study.main.Prototype.Test;
    2. public class Student implements Cloneable {
    3. String name;
    4. private Teacher teacher;
    5. public Teacher getTeacher() {
    6. return teacher;
    7. }
    8. public void setTeacher(Teacher teacher) {
    9. this.teacher = teacher;
    10. }
    11. @Override
    12. protected Object clone() throws CloneNotSupportedException {
    13. Student student = null;
    14. try{
    15. Student clone = (Student) super.clone();
    16. return clone;
    17. }catch (CloneNotSupportedException err) {
    18. err.printStackTrace();
    19. }
    20. return student;
    21. }
    22. }

    教师类 

    1. package com.study.main.Prototype.Test;
    2. public class Teacher implements Cloneable {
    3. String name;
    4. public String getName() {
    5. return name;
    6. }
    7. public void setName(String name) {
    8. this.name = name;
    9. }
    10. @Override
    11. protected Object clone() throws CloneNotSupportedException {
    12. Teacher teacher = null;
    13. try{
    14. Teacher clone = (Teacher) super.clone();
    15. return clone;
    16. }catch (CloneNotSupportedException err) {
    17. err.printStackTrace();
    18. }
    19. return teacher;
    20. }
    21. }

    测试&运行 

    1. package com.study.main.Prototype.Test;
    2. public class TestMain {
    3. public static void main(String[] args) throws CloneNotSupportedException {
    4. // 创建教师
    5. Teacher teacher = new Teacher();
    6. // 设置教师姓名
    7. teacher.setName("A");
    8. // 创建学生
    9. Student stu1 = new Student();
    10. // 设置学生1教师
    11. stu1.setTeacher(teacher);
    12. // 克隆学生1==>学生2
    13. Student stu2 = (Student) stu1.clone();
    14. // 设置学生2教师
    15. stu2.setTeacher(teacher);
    16. // 获取stu2老师
    17. Teacher stu2Teacher = stu2.getTeacher();
    18. // 学生2改变名字
    19. teacher.setName("B");
    20. System.out.println("学生1老师姓名:"+stu1.getTeacher().getName());
    21. System.out.println("学生2老师姓名:"+stu2.getTeacher().getName());
    22. }
    23. }

    结果

    深拷贝

    深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且”修改新对象不会影响原对象。

    只改变上面学生类中的克隆方法让教师对象也进行一边克隆即可

    完整学生类 

    1. package com.study.main.Prototype.Test;
    2. public class Student implements Cloneable {
    3. String name;
    4. private Teacher teacher;
    5. public Teacher getTeacher() {
    6. return teacher;
    7. }
    8. public void setTeacher(Teacher teacher) {
    9. this.teacher = teacher;
    10. }
    11. @Override
    12. protected Object clone() throws CloneNotSupportedException {
    13. Student student = null;
    14. try{
    15. Student clone = (Student) super.clone();
    16. teacher = (Teacher) this.teacher.clone();
    17. return clone;
    18. }catch (CloneNotSupportedException err) {
    19. err.printStackTrace();
    20. }
    21. return student;
    22. }
    23. }

     结果:

    附加Typescript版本

    1. interface Cloneable{
    2. clone():any;
    3. }
    4. class Student implements Cloneable{
    5. public name:string|undefined;
    6. public age:number|undefined;
    7. constructor(name:string,age:number){
    8. this.name = name;
    9. this.age = age;
    10. }
    11. public setName(name:string){
    12. this.name = name
    13. }
    14. clone(): any {
    15. const student:Object =new Object;
    16. const that = this;
    17. Object.assign(student,that)
    18. return student?student:new Error("创建失败");
    19. }
    20. }
    21. const stu1 = new Student('ycw',10);
    22. const stu2:Student = stu1.clone();
    23. stu1.setName("abc")
    24. console.log(stu1,"stu1")
    25. console.log(stu2,"stu2")

    原型模式在JAVA中的应用

    ArrayList 

    ArrayList 中实现了Cloneable接口

     重写clone方法 copyof elementData

    HashMap

    HashMap也实现了Cloneable接口

    原型模式的优缺点 

     优点:

    • 创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效1.
    • 率。
    • 不用重新初始化对象,而是动态地获得对象运行时的状态。
    • 如果原始对象发生变化(增加或者减少属性),其他克隆对象也会发生变化,无需修改
    • 代码。
    • 在实现深克隆的时候可能需要比较复杂的代码

    缺点 

    • 需要为每一个配置类配置一个克隆方法,这对全新的类来说不是很难,但对已有的类进5行改造时,需要修改其源代码,违背了 ocp 原则。(违反开闭原则,如果需要对某个对象进行深克隆则需要对代码进行修改
  • 相关阅读:
    BERT 快速理解——思路简单描述
    [附源码]Python计算机毕业设计高校创新学分申报管理系统
    SPASS-图表的创建&编辑
    sketch有哪些好用的技巧,很少人知道
    2种方法,jmeter用一个正则提取器提取多个值!
    Github高级搜索【指定日期区间,星星数,用户仓库名多条件精确搜索】
    「X」to「Earn」:赛道现状与破局思路
    计算机的基础知识
    ElasticSearch 深度分页解决方案
    nvm (node 版本管理器)
  • 原文地址:https://blog.csdn.net/qq_33839972/article/details/136205336