博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式之原型模式(创建型)
阅读量:2040 次
发布时间:2019-04-28

本文共 4998 字,大约阅读时间需要 16 分钟。

文章目录

模式定义

原型模式(Prototype Pattern):原型模式是提供一个原型接口,提供原型的克隆,创建新的对象,是一种对象创建型模式。

模式结构

原型模式包括如下角色

  • Prototype :抽象原型类
  • ConcretePrototype:具体原型类
  • Client:客户类

原型模式类别

一个类包括另外一个成员变量,在使用原型模式进行对象克隆时,如果直接是通过super Cloneable接口的的clone方法,这种情况其实并不支持类中另外一些成员变量的克隆的,这种方法称之为浅克隆,所以浅克隆和深克隆的本质区别就是看其是否支持类中的成员变量的克隆。

综上,原型模式可以浅克隆和深克隆两种情况,其区别是是否支持类中的成员变量的克隆。

原型模式的浅克隆

原型模式在Java里的常用实现是通过类继承 JDK提供的Cloneable接口,重写 clone(),这种方法其实也可以称之为原型模式的浅克隆

public class A implements Cloneable {		public Object clone()	{		A clone=null;		try		{			clone=(A)super.clone();				}        catch(CloneNotSupportedException e)        {        	System.out.println("Clone failure!");        }		return clone;	}}

一般来说,clone方法符合:

  • 类型相同:对于任何对象a,a.clone().getClass() = a.getClass()
  • 内存地址不同:也可以说对于任何对象a,a.clone()!=a,克隆对象和原对象不是同一个对象
  • a对象的equals方法:对于任何对象a,a.clone().equals(a)

浅克隆的例子,例子来自一书的邮件复制

由于邮件对象包含的内容较多(如发送者、接收者、标题、内容、日期、附件等),某系统中现需要提供一个邮件复制功能,对于已经创建好的邮件对象,可以通过复制的方式创建一个新的邮件对象,如果需要改变某部分内容,无须修改原始的邮件对象,只需要修改复制后得到的邮件对象即可。使用原型模式设计该系统。在本实例中使用浅克隆实现邮件复制,即复制邮件(Email)的同时不复制附件(Attachment)。

附件类:

public class Attachment{    public void download()    {    	System.out.println("下载附件");	    }}

邮件类,浅克隆:

public class Email implements Cloneable {	private Attachment attachment=null;		public Email()	{		this.attachment=new Attachment();	}		public Object clone()	{		Email clone=null;		try		{			clone=(Email)super.clone();				}        catch(CloneNotSupportedException e)        {        	System.out.println("Clone failure!");        }		return clone;	}		public Attachment getAttachment()	{		return this.attachment;	}		public void display()	{		System.out.println("查看邮件");		}	}

客户端类:

public class Client{	public static void main(String a[])	{		Email email,copyEmail;				email=new Email();				copyEmail=(Email)email.clone();				System.out.println("email==copyEmail?");		System.out.println(email==copyEmail);				System.out.println("email.getAttachment==copyEmail.getAttachment?"); 		System.out.println(email.getAttachment()==copyEmail.getAttachment());				}}

编译返回,第一个是false,第二个是true,由前面的理论可以知道,浅克隆对于成员变量是不支持克隆的,因为对象地址还是一样的

原型模式的深克隆

上面是浅克隆的实现,对于原型模式深克隆的实现一般是提供类的序列化来实现

附件类,注意要implements Serializable

import java.io.*;public class Attachment implements Serializable{    public void download()    {        System.out.println("下载附件");    }}

邮件类,同样要实现Serializable接口

import java.io.*;public class Email implements Serializable{	private Attachment attachment=null;	public Email()	{		this.attachment=new Attachment();	}	public Object deepClone() throws IOException, ClassNotFoundException, OptionalDataException	{		//将对象写入流中		ByteArrayOutputStream bao=new ByteArrayOutputStream();		ObjectOutputStream oos=new ObjectOutputStream(bao);		oos.writeObject(this);		//将对象从流中取出		ByteArrayInputStream bis=new ByteArrayInputStream(bao.toByteArray());		ObjectInputStream ois=new ObjectInputStream(bis);		return(ois.readObject());	}	public Attachment getAttachment()	{		return this.attachment;	}	public void display()	{		System.out.println("查看邮件");	}}

客户端类:

public class Client{	public static void main(String a[])	{		Email email,copyEmail=null;		email=new Email();		try{			copyEmail=(Email)email.deepClone();		}		catch(Exception e)		{			e.printStackTrace();		}		System.out.println("email==copyEmail?");		System.out.println(email==copyEmail);		System.out.println("email.getAttachment==copyEmail.getAttachment?");		System.out.println(email.getAttachment()==copyEmail.getAttachment());	}}

编译返回,第一个是false,第二个是flase,由前面的理论可以知道,深克隆对于成员变量是支持克隆的,因为对象地址是一样的

原型管理器

原型管理器是原型模式的拓展
例子同样来自一书

import java.util.*;interface MyColor extends Cloneable{	public Object clone();	public void display();}class Red implements MyColor{   public Object clone()   {     Red r=null;     try     {       r=(Red)super.clone();     }     catch(CloneNotSupportedException e)     {         }     return r;   }   public void display()   {     System.out.println("This is Red!");   }}class Blue implements MyColor{   public Object clone()   {     Blue b=null;     try     {       b=(Blue)super.clone();     }     catch(CloneNotSupportedException e)     {         }     return b;   }   public void display()   {     System.out.println("This is Blue!");   }}class PrototypeManager {   private Hashtable ht=new Hashtable();      public PrototypeManager()   {   	  ht.put("red",new Red());   	  ht.put("blue",new Blue());   }      public void addColor(String key,MyColor obj)   {      ht.put(key,obj);   }      public MyColor getColor(String key)   {      return (MyColor)((MyColor)ht.get(key)).clone();   }}class Client{   public static void main(String args[])   {      PrototypeManager pm=new PrototypeManager();              MyColor obj1=(MyColor)pm.getColor("red");      obj1.display();            MyColor obj2=(MyColor)pm.getColor("red");      obj2.display();            System.out.println(obj1==obj2);   }}

模式应用

原型模式适用的场景

  • 保存对象的状态:对于要保存的状态不是很占内存的情况,可以适用原型模式和备忘录模式保存对象状态,如果对象占用太多内存,那就还是状态模式比较好

  • 创建新对象成本很大的情况:比如创建一个对象是需要查询很慢的SQL才能给对象赋值,这种情况就和适合用原型模式克隆对象,减少对象创建和查询

原型模式应用的场景

  • 对于很多软件的复制和粘贴实现其实也是原型模式的应用
  • Spring框架提供BeanUtils.copyProperties方法也是原型模式的应用

转载地址:http://bfcof.baihongyu.com/

你可能感兴趣的文章
source insight使用方法简介
查看>>
<stdarg.h>头文件的使用
查看>>
C++/C 宏定义(define)中# ## 的含义 宏拼接
查看>>
Git安装配置
查看>>
linux中fork()函数详解
查看>>
C语言字符、字符串操作偏僻函数总结
查看>>
Git的Patch功能
查看>>
分析C语言的声明
查看>>
TCP为什么是三次握手,为什么不是两次或者四次 && TCP四次挥手
查看>>
C结构体、C++结构体、C++类的区别
查看>>
进程和线程的概念、区别和联系
查看>>
CMake 入门实战
查看>>
绑定CPU逻辑核心的利器——taskset
查看>>
Linux下perf性能测试火焰图只显示函数地址不显示函数名的问题
查看>>
c结构体、c++结构体和c++类的区别以及错误纠正
查看>>
Linux下查看根目录各文件内存占用情况
查看>>
A星算法详解(个人认为最详细,最通俗易懂的一个版本)
查看>>
利用栈实现DFS
查看>>
逆序对的数量(递归+归并思想)
查看>>
数的范围(二分查找上下界)
查看>>