首页 > 其他分享 >4. 设计模式--原型模式

4. 设计模式--原型模式

时间:2022-10-11 19:33:47浏览次数:58  
标签:克隆 -- System 对象 原型 user println 设计模式 out

原型模式

  在java中我们知道通过new关键字创建的对象是非常繁琐的(类加载判断,内存分配,初始化等),在我们需要大量对象的情况下,原型模式就是我们可以考虑实现的方式。

原型模式我们也称为克隆模式,即一个某个对象为原型克隆出来一个一模一样的对象,该对象的属性和原型对象一模一样。而且对于原型对象没有任何影响。原型模式的克隆方式有两种:浅克隆和深度克隆

原型模式 说明
浅克隆 只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址
深度克隆 深复制把要复制的对象所引用的对象都复制了一遍

浅克隆

被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。 Object类提供的方法clone只是拷贝本对象 , 其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址

实现

被克隆的对象必须Cloneable,Serializable这两个接口

原型类

package com.dpb.prototype;

import java.io.Serializable;
import java.util.Date;

/**
 * 原型类:被克隆的类型
 * @author dengp
 *
 */
public class User implements Cloneable,Serializable{
	
	private String name;
	
	private Date birth;
	
	private int age;

	public String getName() {
		return name;
	}

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

	public Date getBirth() {
		return birth;
	}

	public void setBirth(Date birth) {
		this.birth = birth;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
	
	/**
	 * 实现克隆的方法
	 */
	public Object clone() throws CloneNotSupportedException{
		return super.clone();
	}
}

测试类

public static void main(String[] args) throws CloneNotSupportedException {
	Date date =  new Date(1231231231231l);
	User user = new User();
	user.setName("波波烤鸭");
	user.setAge(18);
	user.setBirth(date);
	System.out.println("----输出原型对象的属性------");
	System.out.println(user);
	System.out.println(user.getName());
	System.out.println(user.getBirth());
	// 克隆对象
	User user1 =(User) user.clone();
	// 修改原型对象中的属性
	date.setTime(123231231231l);
	System.out.println(user.getBirth());
	
	// 修改参数
	user1.setName("dpb");
	System.out.println("-------克隆对象的属性-----");
	System.out.println(user1);
	System.out.println(user1.getName());
	System.out.println(user1.getBirth());
}

浅克隆的问题:虽然产生了两个完全不同的对象,但是被复制的对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。

深度克隆

被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。
实现的效果是:

深度克隆(deep clone)有两种实现方式,第一种是在浅克隆的基础上实现,第二种是通过序列化和反序列化实现,我们分别来介绍

第一种方式

在浅克隆的基础上实现
原型类:

package com.dpb.prototype;

import java.io.Serializable;
import java.util.Date;

/**
 * 原型类:被克隆的类型
 * 深度克隆测试
 * @author dengp
 *
 */
public class User2 implements Cloneable,Serializable{
	
	private String name;
	
	private Date birth;
	
	private int age;

	public String getName() {
		return name;
	}

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

	public Date getBirth() {
		return birth;
	}

	public void setBirth(Date birth) {
		this.birth = birth;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
	
	/**
	 * 实现克隆的方法
	 * 深度克隆(deep clone)
	 */
	public Object clone() throws CloneNotSupportedException{
		Object object = super.clone();
		// 实现深度克隆(deep clone)
		User2 user = (User2)object;
		user.birth = (Date) this.birth.clone();
		return object;
	}
}

测试代码

public static void main(String[] args) throws CloneNotSupportedException {
	Date date =  new Date(1231231231231l);
	User2 user = new User2();
	user.setName("波波烤鸭");
	user.setAge(18);
	user.setBirth(date);
	System.out.println("----输出原型对象的属性------");
	System.out.println(user);
	System.out.println(user.getName());
	System.out.println(user.getBirth());
	// 克隆对象
	User2 user1 =(User2) user.clone();
	// 修改原型对象中的属性
	date.setTime(123231231231l);
	System.out.println(user.getBirth());
	
	// 修改参数
	user1.setName("dpb");
	System.out.println("-------克隆对象的属性-----");
	System.out.println(user1);
	System.out.println(user1.getName());
	System.out.println(user1.getBirth());
}

我们发现克隆的对象的属性并没有随着我们对Date的修改而改变,说明克隆对象的Date属性和原型对象的Date属性引用的不是同一个对象,实现的深度复制。

第二种方式:序列化和反序列化

名称 说明
序列化 把对象转换为字节序列的过程。
反序列化 把字节序列恢复为对象的过程。
public static void main(String[] args) throws CloneNotSupportedException, Exception {
	Date date =  new Date(1231231231231l);
	User user = new User();
	user.setName("波波烤鸭");
	user.setAge(18);
	user.setBirth(date);
	System.out.println("-----原型对象的属性------");
	System.out.println(user);
	System.out.println(user.getName());
	System.out.println(user.getBirth());
	
	//使用序列化和反序列化实现深复制
	ByteArrayOutputStream bos = new ByteArrayOutputStream();
	ObjectOutputStream    oos = new ObjectOutputStream(bos);
	oos.writeObject(user);
	byte[] bytes = bos.toByteArray();
	
	ByteArrayInputStream  bis = new ByteArrayInputStream(bytes);
	ObjectInputStream	  ois = new ObjectInputStream(bis);
	
	//克隆好的对象!
	User user1 = (User) ois.readObject();   
	
	// 修改原型对象的值
	date.setTime(221321321321321l);
	System.out.println(user.getBirth());
	
	System.out.println("------克隆对象的属性-------");
	System.out.println(user1);
	System.out.println(user1.getName());
	System.out.println(user1.getBirth());
}

实现了和第一种实现方式相同的效果~实现了深度克隆

原型模式和直接new对象方式的比较

当我们需要大量的同一类型对象的时候可以使用原型模式,下面是两种方式的性能对比:

用两种方式同时生成10个对象

/**
 * 测试普通new方式创建对象和clone方式创建对象的效率差异!
 * 如果需要短时间创建大量对象,并且new的过程比较耗时。则可以考虑使用原型模式!
 * @author 波波烤鸭
 *
 */
public class Client4 {
	
	public static void testNew(int size){
		long start = System.currentTimeMillis();
		for(int i=0;i<size;i++){
			User t = new User();
		}
		long end = System.currentTimeMillis();
		System.out.println("new的方式创建耗时:"+(end-start));
	}
	
	public static void testClone(int size) throws CloneNotSupportedException{
		long start = System.currentTimeMillis();
		User t = new User();
		for(int i=0;i<size;i++){
			User temp = (User) t.clone();
		}
		long end = System.currentTimeMillis();
		System.out.println("clone的方式创建耗时:"+(end-start));
	}
	
	
	public static void main(String[] args) throws Exception {	
		testNew(10);
		testClone(10);
	}
}


class User implements Cloneable {  //用户
	public User() {
		try {
			Thread.sleep(10);  //模拟创建对象耗时的过程!
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		Object obj = super.clone();  //直接调用object对象的clone()方法!
		return obj;
	}
}

输出结果:

new的方式创建耗时:108
clone的方式创建耗时:11

用两种方式同时生成1000个对象


/**
 * 测试普通new方式创建对象和clone方式创建对象的效率差异!
 * 如果需要短时间创建大量对象,并且new的过程比较耗时。则可以考虑使用原型模式!
 * @author 波波烤鸭
 *
 */
public class Client4 {
	
	public static void testNew(int size){
		long start = System.currentTimeMillis();
		for(int i=0;i<size;i++){
			User t = new User();
		}
		long end = System.currentTimeMillis();
		System.out.println("new的方式创建耗时:"+(end-start));
	}
	
	public static void testClone(int size) throws CloneNotSupportedException{
		long start = System.currentTimeMillis();
		User t = new User();
		for(int i=0;i<size;i++){
			User temp = (User) t.clone();
		}
		long end = System.currentTimeMillis();
		System.out.println("clone的方式创建耗时:"+(end-start));
	}
	
	
	public static void main(String[] args) throws Exception {	
		testNew(1000);
		testClone(1000);
	}
}


class User implements Cloneable {  //用户
	public User() {
		try {
			Thread.sleep(10);  //模拟创建对象耗时的过程!
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		Object obj = super.clone();  //直接调用object对象的clone()方法!
		return obj;
	}
}

输出结果:

new的方式创建耗时:10836
clone的方式创建耗时:10

小结:通过clone的方式在获取大量对象的时候性能开销基本没有什么影响,而new的方式随着实例的对象越来越多,性能会急剧下降,所以原型模式是一种比较重要的获取实例的方式。大家应该掌握好。

开发中的应用场景

原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者。
• spring中bean的创建实际就是两种:单例模式和原型模式。(原型模式需要和工厂模式搭配起来)

标签:克隆,--,System,对象,原型,user,println,设计模式,out
From: https://www.cnblogs.com/ytmm/p/16773615.html

相关文章

  • 二叉树广义表的算法生成 (A(B(,D(E,F)),C))
     #include<stdio.h>#include<stdlib.h>typedefcharDataType;typedefstructnode{DataTypedata;structnode*lchild,*rchild;}BinTNode;ty......
  • 实验5:开源控制器实践——POX
    (一)基本要求1、搭建下图所示SDN拓扑,协议使用OpenFlow1.0,控制器使用部署于本地的POX(默认监听6633端口)2、阅读Hub模块代码,使用tcpdump验证Hub模块;h1pingh3h1ping......
  • 网络质量测试
    iperf工具:网络性能测试工具iperf的使用-知乎(zhihu.com)网络性能评估工具Iperf详解(可测丢包率)_bingyu9875的博客-CSDN博客_iperf windows下:测抖动丢包率参数......
  • Python基础12
    今日内容概要global与nonlocal函数名的多种用法闭包函数装饰器简介装饰器推导流程装饰器模板装饰器语法糖今日内容详细global与nonlocal'''通过global声明可......
  • VS2019 添加三方文件夹遇到的坑
    在开发新项目时需要用到一些三方API,这些三方API没有生成lib,所以我们在VS编译器中添加这些三方文件夹的头文件路径后会出现ERRORLNK2019的错误提示,这些提示通常都......
  • 做题记录整理栈7 P1950 长方形(2022/10/11)
    P1950长方形玉蟾宫升级版#include<bits/stdc++.h>#definefor1(i,a,b)for(inti=a;i<=b;i++)#definelllonglong#definemp(a,b)make_pair(a,b)usingnamespa......
  • OTA 细节学习
    定义为了便于理解,我们假设:一张图片上有3个目标框,即3个groundtruth项目有2个检测类别,比如cat/dog网络输出1000个预测框,其中只有少部分是正样本,绝大多数是负样本......
  • 五.不同请求的获取方式
    http不同请求方法的处理: GET:获取服务器资源POST:向服务器提交数据PUT:向服务器写入资源,如果已存在则进行替换DELETE:......
  • 六.express框架基础使用
    express框架1.特性: 上手简单,学习门槛低具有丰富的基础API支持强大的路由功能灵活的中间件机制及吩咐的第三方中间支持性能接近原生Node......
  • 今日内容 内置认证类,权限类和频率类
    内置认证类,权限类,频率类内置的认证类BasicAuthenticationRemoteUserAuthenticationSessionAuthentication:#session认证,建议自己写#如果前端带着cookie过来,......