首页 > 其他分享 >【设计模式与体系结构】创建型模式-原型模式

【设计模式与体系结构】创建型模式-原型模式

时间:2025-01-10 22:12:46浏览次数:1  
标签:stu2 stu1 System 模式 println 设计模式 out public 体系结构

简介

原型模式(Prototype Pattern)指的是用一个已经创建的对象作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。

原型模式的角色

  1. 抽象原型类:规定具体原型对象必须实现的 \(clone()\) 方法
  2. 具体原型类:实现抽象原型类的 \(clone()\) 方法,它是可被复制的对象
  3. 访问类:使用具体原型类的 \(clone()\) 方法来复制新的对象

原型模式的类型

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

原型模式的使用场景

  1. 对象的创建过程十分复杂,可以使用原型模式快速创建对象
  2. 性能和安全要求比较高

正文

浅克隆

世上第一只克隆羊 Dolly 人尽皆知,下面就以此写一份代码:
母羊的代码:

public class Sheep implements Cloneable {
    private String gene;//非基本类型,因此浅克隆得到的是引用类型
    
    @NonNull
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public String getGene() {
        return gene;
    }

    public void setGene(String gene) {
        this.gene = gene;
    }
}

克隆出 Dolly 的代码:

private void shallowClone() {
    Sheep mother = new Sheep();
    mother.setGene("456");
    try {
        Sheep Dolly = (Sheep) mother.clone();
        Log.i("Clone", "mother == Dolly? " + (mother == Dolly));
        Log.i("Clone", (mother.getGene() == Dolly.getGene()) + "");
    } catch (CloneNotSupportedException e) {
        throw new RuntimeException(e);
    }
}

运行截图如下:

由上述代码不难看出,实现 \(Cloneable\) 接口的克隆方式是一种浅克隆。Dolly 和母羊明显是不同的个体,但是有相同的基因片段(视为引用类型),因此使用浅克隆是合适的。

对于引用类型的浅克隆,我们有一个共识:修改克隆的对象的引用类型属性后,被克隆对象的对应属性也一同修改(准确点说是修改的同一个属性)。不妨对 Dolly 的案例进行测试:

private void shallowClone() {
    Sheep mother = new Sheep();
    mother.setGene("456");
    try {
        Sheep Dolly = (Sheep) mother.clone();
        Log.i("Clone", "mother == Dolly? " + (mother == Dolly));
        Log.i("Clone", (mother.getGene() == Dolly.getGene()) + "");
        Dolly.setGene("123");
        Log.i("Clone", (mother.getGene() == Dolly.getGene()) + "");
    } catch (CloneNotSupportedException e) {
        throw new RuntimeException(e);
    }
}

运行截图如下:

既然对于非基本类型的浅克隆都是引用类型,为什么会出现修改 Dolly 的 String 类型的 gene 属性时,母羊没有同时修改呢?
答:String 类型虽然属于非基本类型,但是 Java 存在常量池机制,不同的 String 类型字符串都会存储在常量池中,因此不同对象的 gene 指向了不同的地址。

因此我们需要对 String 这个非基本类型特别看待,那么我们不妨用其他非基本类型的数据对“引用类型”这个性质进行验证。

深克隆

假设同学 A 和同学 B 是同班同学。每个学生都有姓名、性别等属性,这些属性都是非基本类型 String,也有年龄(int)、身高(float)等属性,这些属性都是基本类型。
对每个同学而言,都具备姓名、性别、年龄和身高等属性,且是个人特有的。假设我们想由同学 A 对象克隆出同学 B 对象,那么非基本类型再使用浅克隆就不合适了。因为两位同学的名字、性别等明显是不共享的,因此不可以使用引用类型,而是要用拷贝类型,所以要使用深克隆。

对于深克隆的参考文章为:https://www.cnblogs.com/gollong/p/9668699.html

对于引用类型,我们将其也实现 Cloneable 接口,这样子就可以使得引用类型的属性也变为拷贝类型

实现方式一:clone()函数的嵌套调用

定义一个学生类 Student.java

学生类
public class Student implements Cloneable {
	private Information information;
	private int schoolId;
	
	public Student(int schoolId, int age, float height) {
		this.schoolId = schoolId;
		this.information = new Information(age, height);
	}
	
	public Information getInformation() {
		return information;
	}
	
	public void setInformation(Information information) {
		this.information = information;
	}
	
	public int getSchoolId() {
		return schoolId;
	}
	
	public void setSchoolId(int schoolId) {
		this.schoolId = schoolId;
	}

	@Override
	public Student clone() throws CloneNotSupportedException {
		Student student = (Student) super.clone();
		student.information = (Information) information.clone();
		return student;
	}
}

定义一个信息类 Information.java

信息类
public class Information implements Cloneable {
	private int age;
	private float height;
	
	public Information(int age, float height) {
		this.age = age;
		this.height = height;
	}
	
	public int getAge() {
		return age;
	}
	
	public void setAge(int age) {
		this.age = age;
	}
	
	public float getHeight() {
		return height;
	}
	
	public void setHeight(float height) {
		this.height = height;
	}

	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}

	@Override
	public String toString() {
		return "age: " + getAge() + "  height: " + getHeight();
	}
	
}

测试深克隆模式实现方式一

clone() 方法的嵌套调用测试
private void testDeepClone() {
    Student stu1 = new Student(1, 15, 165.5f);
    try {
        Student stu2 = stu1.clone();
  	    System.out.println("修改前:");
  	    System.out.println(stu1.toString() + " " + stu2.toString() + " 相等与否?" + stu1.toString().equals(stu2.toString()));
  	    System.out.println("stu1的信息:" + stu1.getSchoolId() + " " + stu1.getInformation());
  	    System.out.println("stu2的信息:" + stu2.getSchoolId() + " " + stu2.getInformation());
  	    System.out.println("学校:" + (stu1.getSchoolId() == stu2.getSchoolId()));
  	    System.out.println("信息:" + (stu1.getInformation() == stu2.getInformation()));
  			
  	    System.out.println("修改后:");
  	    stu1.setSchoolId(2);
  	    stu2.getInformation().setAge(18);
  	    stu2.getInformation().setHeight(175.3f);
  	    System.out.println(stu1.toString() + " " + stu2.toString() + " 相等与否?" + stu1.toString().equals(stu2.toString()));
  	    System.out.println("stu1的信息:" + stu1.getSchoolId() + " " + stu1.getInformation());
  	    System.out.println("stu2的信息:" + stu2.getSchoolId() + " " + stu2.getInformation());
  	    System.out.println("学校:" + (stu1.getSchoolId() == stu2.getSchoolId()));
  	    System.out.println("信息:" + (stu1.getInformation() == stu2.getInformation()));
    } catch (CloneNotSupportedException e) {
  	    e.printStackTrace();
    }
}

运行截图如下:

实现方式二:序列化

clone() 方法的嵌套调用,已经可以实现深克隆的需求。但是当所要克隆的类嵌套深度较大,或者数据结构较为复杂的情况下,方式一就略显复杂,并且不符合开闭原则。而序列化只需要为每一个类实现一个 Serializable 接口,最后通过序列化和反序列化即可实现深克隆。

定义一个学生类 Student.java

学生类
public class Student implements Serializable {
	private Information information;
	private int schoolId;
	
	public Student(int schoolId, int age, float height) {
		this.schoolId = schoolId;
		this.information = new Information(age, height);
	}
	
	public Information getInformation() {
		return information;
	}
	
	public void setInformation(Information information) {
		this.information = information;
	}
	
	public int getSchoolId() {
		return schoolId;
	}
	
	public void setSchoolId(int schoolId) {
		this.schoolId = schoolId;
	}
}

定义一个信息类 Information.java

信息类
public class Information implements Serializable {
	private int age;
	private float height;
	
	public Information(int age, float height) {
		this.age = age;
		this.height = height;
	}
	
	public int getAge() {
		return age;
	}
	
	public void setAge(int age) {
		this.age = age;
	}
	
	public float getHeight() {
		return height;
	}
	
	public void setHeight(float height) {
		this.height = height;
	}

	@Override
	public String toString() {
		return "age: " + getAge() + "  height: " + getHeight();
	}
	
}

测试深克隆模式实现方式二

序列化测试
private void testDeepClone() {
	Student stu1 = new Student(1, 15, 165.5f);
	ByteArrayOutputStream baos = new ByteArrayOutputStream();
	ObjectOutputStream oos;
	try {
		oos = new ObjectOutputStream(baos);
		oos.writeObject(stu1);
		ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
		ObjectInputStream ois = new ObjectInputStream(bais);
		Student stu2 = (Student) ois.readObject();
		System.out.println("修改前:");
		System.out.println(stu1.toString() + " " + stu2.toString() + " 相等与否?" + stu1.toString().equals(stu2.toString()));
		System.out.println("stu1的信息:" + stu1.getSchoolId() + " " + stu1.getInformation());
		System.out.println("stu2的信息:" + stu2.getSchoolId() + " " + stu2.getInformation());
		System.out.println("学校:" + (stu1.getSchoolId() == stu2.getSchoolId()));
		System.out.println("信息:" + (stu1.getInformation() == stu2.getInformation()));
			
		System.out.println("修改后:");
		stu1.setSchoolId(2);
		stu2.getInformation().setAge(18);
		stu2.getInformation().setHeight(175.3f);
		System.out.println(stu1.toString() + " " + stu2.toString() + " 相等与否?" + stu1.toString().equals(stu2.toString()));
		System.out.println("stu1的信息:" + stu1.getSchoolId() + " " + stu1.getInformation());
		System.out.println("stu2的信息:" + stu2.getSchoolId() + " " + stu2.getInformation());
		System.out.println("学校:" + (stu1.getSchoolId() == stu2.getSchoolId()));
		System.out.println("信息:" + (stu1.getInformation() == stu2.getInformation()));
	} catch (IOException e) {
		e.printStackTrace();
	} catch (ClassNotFoundException e) {
		e.printStackTrace();
	}
}

运行截图如下:

标签:stu2,stu1,System,模式,println,设计模式,out,public,体系结构
From: https://www.cnblogs.com/RomanLin/p/18623351

相关文章

  • 想在linux平台拥有和vs一样的体验模式吗?只需配置一下你的vim便可以轻松达到,让你日常
            ......
  • 第五章 保护模式进阶,向内核迈进
    第五章保护模式进阶,向内核迈进本文是对《操作系统真象还原》第五章学习的笔记,欢迎大家一起交流。a获取物理内存知识部分为了在后期做好内存管理工作,咱们先得知道自己有多少物理内存才行。所以现在的工作是为了获取物理内存,一共介绍三种方法,都是利用的BIOS0x15中断,三种方......
  • 设计模式--迭代器模式【行为型模式】
    设计模式的分类我们都知道有23种设计模式,这23种设计模式可分为如下三类:创建型模式(5种):单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。结构型模式(7种):适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。行为型模式(11种):策略......
  • 十个经典的Java面试题及详解,这些问题涵盖了Java语言特性、多线程、JVM、设计模式、框
    1.Java内存模型(JMM)问题:请解释Java内存模型(JMM)的基本概念。答案:Java内存模型(JMM)定义了多线程程序中变量的访问规则。JMM的主要目标是确保程序在多线程环境下的正确性和性能。JMM主要包括以下几点:主内存与工作内存:所有变量都存储在主内存中,每个线程有自己的工作内存,线程对变......
  • C++项目Visual Studio 如何在Release编译模式下断点调试
    在VS中,Debug编译模式下通常是默认支持断点调试的,但有时项目需要会需要在Release编译模式下进行打断点调试原因无外乎三点:Debug模式下编译运行无异常,但Release下出现问题需要release下屏蔽断言和部分宏定义win平台的动态库区分release和debug模式,部分项目......
  • 目标客户营销(ABM)结合开源AI智能名片2+1链动模式S2B2C商城小程序的策略与实践
    摘要:在数字化营销日益盛行的今天,目标客户营销(AccountBasedMarketing,ABM)作为一种高度定制化的营销策略,正逐步成为企业获取高质量客户、提升市场竞争力的重要手段。与此同时,开源AI智能名片2+1链动模式S2B2C商城小程序作为一种创新的数字化营销工具,以其强大的数据分析、智能推......
  • 基于开源AI智能名片2+1链动模式S2B2C商城小程序的企业数字化转型深度策略与实践
    摘要:在大数据、人工智能等前沿技术的推动下,企业数字化转型已成为提升竞争力的关键路径。开源AI智能名片2+1链动模式S2B2C商城小程序作为一种创新工具,凭借其强大的数据分析、智能推荐及社交裂变能力,为企业提供了一个从用户洞察、产品优化到供应链管理的全方位解决方案。本文旨在......
  • 责任链模式详解
    责任链模式详解1.定义责任链模式(ChainofResponsibilityPattern)是一种行为型设计模式,它允许将请求沿着处理者链进行传递,直到某个处理者能够处理该请求为止。这种模式通过将请求的发送者和接收者解耦,将请求沿着一条链传递,直到链上的某个节点能够处理该请求。2.主要角色......
  • [读书日志]从零开始学习Chisel 第十篇:Scala的模式匹配(敏捷硬件开发语言Chisel与数字系
    7.Scala的模式匹配7.1样例类和对象定义类时,如果在最前面加上关键字case,则这个类就被称为样例类。Scala的编译器自动对样例类添加一些语法便利:添加一个与类同名的工厂方法,可以通过类名(参数)来构造对象,而不需要使用new类名(参数)来构造;参数列表的每个参数都隐式地获得......
  • 大闹天宫更始版H5网页游戏一键端+GM模式+安装教程
    今天为大家带来一款怀旧网单《大闹天宫更始版H5网页游戏》的游戏架设,仅供怀旧,本人已经安装游戏成功,特此带来详细安装教程。视频演示https://githubs.xyz/show/331.mp4 亲测截图   架设步骤关闭默认杀毒软件和其它自己下的杀毒软件 ,一定要检查关闭!!!!  打开windows......