设计模式——原型模式

定义:

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

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

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

工作原理:

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

原型模式组成

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

例子:

克隆源

java 复制代码
package com.study.main.Prototype;

public class CloneSource implements Cloneable{

    public String getName() {
        return "克隆源";
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        CloneSource cloneSource = null;
        try{
            cloneSource = (CloneSource) super.clone();
        }
        catch (CloneNotSupportedException err){
            err.printStackTrace();
        }
        return cloneSource;
    }
}

克隆1类

java 复制代码
package com.study.main.Prototype;

public class CloneTest1 extends CloneSource{
    public void show(){
        System.out.println("测试克隆1");
    }
}

克隆2类

java 复制代码
package com.study.main.Prototype;

public class CloneTest2 extends CloneSource{
    public void show(){
        System.out.println("测试克隆2");
    }
}

实现类

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

java 复制代码
package com.study.main.Prototype;

public class PrototypeMain {
    public static void main(String[] args) throws CloneNotSupportedException {
        CloneTest1 cloneSource = new CloneTest1();
        CloneTest2 cloneSource2 = new CloneTest2();
        for (int i = 0; i < 2; i++) {
            CloneTest1 cloneTest= (CloneTest1) cloneSource.clone();
            cloneTest.show();
            System.out.println(cloneTest.getName());
        }
        for (int i = 0; i < 2; i++) {
            CloneTest2 cloneTest2= (CloneTest2) cloneSource2.clone();
            cloneTest2.show();
            System.out.println(cloneTest2.getName());
        }
    }
}

结果:

注意 :

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

深拷贝&浅拷贝

浅拷贝

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

例子:

学生类:

java 复制代码
package com.study.main.Prototype.Test;

public class Student implements Cloneable {
    String name;
    private Teacher teacher;

    public Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Student student = null;
        try{
            Student clone = (Student) super.clone();
            return clone;
        }catch (CloneNotSupportedException err) {
            err.printStackTrace();
        }
        return student;
    }
}

教师类

java 复制代码
package com.study.main.Prototype.Test;

public class Teacher implements Cloneable {
    String name;

    public String getName() {
        return name;
    }

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

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Teacher teacher = null;

        try{
            Teacher clone = (Teacher) super.clone();
            return clone;
        }catch (CloneNotSupportedException err) {
            err.printStackTrace();
        }
        return teacher;
    }
}

测试&运行

java 复制代码
package com.study.main.Prototype.Test;

public class TestMain {
    public static void main(String[] args) throws CloneNotSupportedException {
        // 创建教师
        Teacher teacher = new Teacher();
        // 设置教师姓名
        teacher.setName("A");
        // 创建学生
        Student stu1 = new Student();
        // 设置学生1教师
        stu1.setTeacher(teacher);
        // 克隆学生1==>学生2
        Student stu2 = (Student) stu1.clone();
        // 设置学生2教师
        stu2.setTeacher(teacher);
        // 获取stu2老师
        Teacher stu2Teacher = stu2.getTeacher();
        // 学生2改变名字
        teacher.setName("B");
        System.out.println("学生1老师姓名:"+stu1.getTeacher().getName());
        System.out.println("学生2老师姓名:"+stu2.getTeacher().getName());
    }
}

结果

深拷贝

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

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

完整学生类

java 复制代码
package com.study.main.Prototype.Test;

public class Student implements Cloneable {
    String name;
    private Teacher teacher;

    public Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Student student = null;
        try{
            Student clone = (Student) super.clone();
            teacher = (Teacher) this.teacher.clone();
            return clone;
        }catch (CloneNotSupportedException err) {
            err.printStackTrace();
        }
        return student;
    }
}

结果:

附加Typescript版本

TypeScript 复制代码
interface Cloneable{
   clone():any;
}
class Student implements Cloneable{
    public name:string|undefined;
    public age:number|undefined;
    constructor(name:string,age:number){
        this.name = name;
        this.age = age;
    }
    public setName(name:string){
        this.name = name
    }
    clone(): any { 
        const student:Object =new Object;
        const that = this;
        Object.assign(student,that)
        return student?student:new Error("创建失败");
    }
}
const stu1 = new Student('ycw',10);
const stu2:Student = stu1.clone();
stu1.setName("abc")
console.log(stu1,"stu1")
console.log(stu2,"stu2")

原型模式在JAVA中的应用

ArrayList

ArrayList 中实现了Cloneable接口

重写clone方法 copyof elementData

HashMap

HashMap也实现了Cloneable接口

原型模式的优缺点

优点:

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

缺点

  • 需要为每一个配置类配置一个克隆方法,这对全新的类来说不是很难,但对已有的类进5行改造时,需要修改其源代码,违背了 ocp 原则。(违反开闭原则,如果需要对某个对象进行深克隆则需要对代码进行修改)
相关推荐
THRUSTER1111122 分钟前
Java学习笔记--继承的介绍,基本使用,成员变量和成员方法访问特点
java·开发语言·笔记·学习·学习方法·继承·intellij idea
沉河不浮23 分钟前
Java基础——(一)Java概述
java·开发语言
paterWang24 分钟前
小程序-基于java+SpringBoot+Vue的网上花店微信小程序设计与实现
java·spring boot·小程序
paterWang43 分钟前
小程序-基于java+SpringBoot+Vue的美食推荐系统设计与实现
java·spring boot·小程序
《源码好优多》44 分钟前
基于Java Springboot餐饮美食分享平台
java·spring boot·美食
说书客啊1 小时前
计算机毕业设计 | SpringBoot+vue美食推荐商城 食品零食购物平台(附源码+论文)
java·spring boot·node.js·vue·毕业设计·课程设计·美食
小宋10211 小时前
实现java执行kettle并传参数
java·开发语言·etl
贝克街的天才1 小时前
据说在代码里拼接查询条件不够优雅?Magic-1.0.2 发布
java·后端·开源
神仙别闹2 小时前
基于Java实现的(GUI)华容道小游戏
java·gui
JosieBook2 小时前
【面试题】2025年百度校招Java后端面试题
java·开发语言·网络·百度