设计模式学习笔记(十三:原型模式)

1.1概述

    用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。这就是原型模式的定义。

  在某些情况下,可能不希望反复使用类的构造方法创建许多对象,而是希望使用该类创建一个对象后,以该对象为原型得到该对象的若干个复制品。也就是说,将一个对象定义为原型对象,要求改原型对象提供一个方法,使该原型对象调用此方法可以复制一个和自己有完全相同状态的同类型对象,即该方法“克隆”原型对象得到一个新对象。原型对象和以它为原型“克隆”出的新对象可以分别独立地变化,也就是说,原型对象改变其状态不会影响到以它为原型“克隆”出的新对象,反之也一样。

  例如,通过复制一个已有的Word文档中的文本创建一个新的Word文档后,两个文档中的文本内容可独立地变化互不影响。

    原型模式是从一个对象出发得到一个和自己有相同状态的新对象的成熟模式,该模式的关键是将一个对象定义为原型,并为其提供复制自己的方法。

 

1.2模式的结构

原型模式结构包括两种角色:

(1)抽象原型(Prototype):一个接口,负责定义对象复制自身的方法。

(2)具体原型(ConcretePrototype):实现Prototype接口的类,具体原型实现抽象原型中的方法,以便所创建的对象调用该方法复制自己。

原型模式结构的类图如下图所示:

 

 

图一:原型模式结构的类图

 

 

1.3原型模式的优点

1)当创建类的新实例的代价更大时,使用原型模式复制一个已有的实例可以提高创建新实例的效率。

2)可以动态地保持当前对象的动态。在运行时,可以随时使用对象流保存当前对象的一个复制品。

3)可以在运行时创建新的对象,而无须创建一系列类和继承结构。

4)可以动态地添加、删除原型的复制品。

 

1.4适合使用原型模式的情景

1)程序需要从一个对象出发,得到若干个和其状态相同,并可独立变化其状态的对象时。

2)当对象的创建需要独立于它的构造过程和表示时。

3)一个类创建实例状态不是很多,那么就可以将这个类的一个实例定义为原型,那么通过复制该原型得到新的实例可能比重新使用类的构造方法创建新实例更方便。

 

 

1.5原型模式的使用

以下通过一个简单的问题:克隆一个立方体和一个山羊来描述原型模式中所涉及的各个角色,具体如下:

 首先看一下本实例构建框架具体类和1.2模式的结构中类图的对应关系,如下图所示:

 

(1)抽象原型(Prototype

抽象原型是Prototype接口,该接口的代码如下:

package com.liuzhen.thirteen_prototype;public interface Prototype {public Object cloneMe() throws CloneNotSupportedException;
}

 

(2)具体原型(Concrete Prototype

具体原型是Cubic类和Goat类。Goat类使用对象序列化来复制对象,Java类库中的绝大多数类都实现了Serializable接口,比如StringBuffer类以及java.awt包中的组件类等。Cubic类和Goat类的代码如下:

 Cubic.java

package com.liuzhen.thirteen_prototype;public class Cubic implements Prototype , Cloneable{double length , width , height;Cubic(double a,double b,double c){length = a;width = b;height = c;}public Object cloneMe() throws CloneNotSupportedException{Cubic object = (Cubic) clone();return object;}
}

Goat.java

package com.liuzhen.thirteen_prototype;import java.io.*;@SuppressWarnings("serial")
public class Goat implements Prototype , Serializable{StringBuffer color;public void setColor(StringBuffer c){color = c;}public StringBuffer getColor(){return color;}public Object cloneMe() throws CloneNotSupportedException{Object object = null;try{ByteArrayOutputStream outOne = new ByteArrayOutputStream();ObjectOutputStream outTwo = new  ObjectOutputStream(outOne);outTwo.writeObject(this);      //将原型对象写入对象输出流ByteArrayInputStream inOne = new ByteArrayInputStream(outOne.toByteArray());ObjectInputStream inTwo = new ObjectInputStream(inOne);object = inTwo.readObject();   //创建新的对象;原型的复制品
        }catch(Exception event){System.out.println(event);}return object;}
}

 

(3)模式的具体使用

 通过ThirTeenApplication类来具体实现上述相关类和接口,来实现原型模式的运用,其代码如下:

package com.liuzhen.thirteen_prototype;public class ThirteenApplication {public static void main(String[] args){Cubic cubic = new Cubic(12,20,66);System.out.println("cubic的长、宽和高:");System.out.println(cubic.length+","+cubic.width+","+cubic.height);try{Cubic cubicCopy = (Cubic) cubic.cloneMe();System.out.println("cubicCopy的长、宽和高:");System.out.println(cubicCopy.length+","+cubicCopy.width+","+cubicCopy.height);}catch(CloneNotSupportedException exp){}Goat goat = new Goat();goat.setColor(new StringBuffer("白颜色的山羊"));System.out.println("goat是"+goat.getColor());try{Goat goatCopy = (Goat)goat.cloneMe();System.out.println("goatCopy是"+goatCopy.getColor());System.out.println("goatCopy将自己的颜色变成黑色");goatCopy.setColor(new StringBuffer("黑颜色的山羊"));System.out.println("goat仍然是"+goat.getColor());System.out.println("goatCopy是"+goatCopy.getColor());}catch(CloneNotSupportedException exp){}}
}

 

运行结果:

cubic的长、宽和高:
12.0,20.0,66.0
cubicCopy的长、宽和高:
12.0,20.0,66.0
goat是白颜色的山羊
goatCopy是白颜色的山羊
goatCopy将自己的颜色变成黑色
goat仍然是白颜色的山羊
goatCopy是黑颜色的山羊

 

 

参考资料:

      1.Java设计模式/耿祥义,张跃平著.——北京:清华大学出版社,2009.5

转载于:https://www.cnblogs.com/liuzhen1995/p/6031797.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/372092.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

翻译的一篇关于学习编程语言的小文章

Top programming languages to get a job in Toronto in 2017 在程序开发人员和软件工程师中最容易被提及的问题之一就是:“我要学的下一门编程语言该是谁?” 我想去选一个编程语言,我希望你能给我一些关于经常使用到的编程语言的建议&#x…

从linux内核启动,学习Linux内核启动过程:从start_kernel到init

一、实验步骤:1:运行menuos:a)cd LinuxKernel/b)qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img启动后启动了MenuOS。2:使用gdb调试跟踪menuos内核启动和运行过程;a)qemu -kernel linux-3.18.6/arch/x86/bo…

【转】nginx的优缺点

原博文出自于:http://blog.csdn.net/a454211787/article/details/22494485 感谢! 1、nginx相对于apache优点: 轻量级同样起web 服务比apache占用更少内存及资源 抗并发nginx 处理请求异步非阻塞而apache 则阻塞型高并发下nginx 能保持低资源低消耗高…

与Maven 3,Failsafe和Cargo插件的集成测试

开箱即用,可以在Maven中进行单元测试。 因此,它也经常用于集成测试。 这样做的主要缺点是集成测试可能需要花费更多的时间来执行,并且因为没有人喜欢每次构建都要等待很长时间–使用-Dmaven.test.skiptrue标志可以跳过测试 为了执行与Maven的…

Spring入门第二十五课

使用具名参数 直接看代码&#xff1a; db.properties jdbc.userroot jdbc.passwordlogan123 jdbc.driverClasscom.mysql.jdbc.Driver jdbc.jdbcUrljdbc:mysql://localhost:3306/selective-courses-systemjdbc.initPoolSize5 jdbc.maxPoolSize10 applicationContext.xml <?x…

linux强制回收内存,Linu系统cache强制回收

LINUX的内存管理机制&#xff0c;一般情况下不需要特意去释放已经使用的cache。Cache机制的存在&#xff0c;使得Linux对磁盘的读写速度是有较大的好处的。 在 Linux 操作系统中&#xff0c;当应用程序需要读取文件中的数据时&#xff0c;操作系统先分配一些内存&#xff0c;将…

HDU 1412 {A} + {B}

Problem Description给你两个集合。要求{A} {B}.注:同一个集合中不会有两个同样的元素.Input每组输入数据分为三行,第一行有两个数字n,m(0<n,m<10000),分别表示集合A和集合B的元素个数.后两行分别表示集合A和集合B.每一个元素为不超出int范围的整数,每一个元素之间有一个…

Google API:如何访问Google Analytics(分析)数据?

在深入研究Google Analytics&#xff08;分析&#xff09;API之前&#xff0c;了解一些Google Analytics&#xff08;分析&#xff09;术语及其关系总是很有用的。 Google帐户&#xff1a;要访问Google Analytics&#xff08;分析&#xff09;&#xff0c;用户将需要一个Google…

为什么linux的新得立软件下载,linux,debian_蝶变(Debian)_Xfce_新立得软件管理_安装不上软件了,怎么处理?,linux,debian - phpStudy...

蝶变(Debian)_Xfce_新立得软件管理_安装不上软件了,怎么处理&#xff1f;(synaptic:9573): GLib-CRITICAL **: g_child_watch_add_full: assertion pid > 0 failed正在预设定软件包 ...(正在读取数据库 ... 系统当前共安装有 343467 个文件和目录。)正准备解包 .../libc6-db…

设计模式学习笔记(十六:桥接模式)

1.1概述 将抽象部分与它的实现部分分离&#xff0c;使他们都可以独立地变化。这就是桥接模式的定义。 抽象类或接口中可以定义若干个抽象方法&#xff0c;习惯上将抽象方法称作操作。抽象类或接口使程序的设计者忽略操作的细节&#xff0c;即不必考虑这些操作是如何实现的&…

Request的getParameter和getAttribute方法的差别

HttpServletRequest.getParameter("modelName");能取到想要的modelObject吗&#xff1f;经过測试之后。发现是不能的。后来想想。其它道理挺简单的&#xff0c;当两个Web组件之间为转发关系时&#xff0c;转发源会将要共享request范围内的数据先用setAttribute将数据…

Spring Social入门–第2部分

几周前&#xff0c;我写了一篇文章&#xff0c;展示了我认为可以使用Spring Social编写的最简单的应用程序。 该应用程序读取并显示了Twitter用户的公共数据&#xff0c;并被编写为Spring Social和社交编码领域的介绍。 但是&#xff0c;让您的应用程序显示用户的公共数据只是故…

linux静默删除文件夹,Linux常用命令10 - unzip

zip 是最广泛使用的归档文件, 除了linux&#xff0c;windows也是非常的广泛。&#xff0c;支持无损数据压缩。 zip 文件是包含一个或多个压缩文件或目录的数据容器。接下来&#xff0c;我将解释如何使用 unzip 命令通过命令行解压缩 Linux 系统中的文件。 还有与之对应就是 zip…

Git学习笔记(一) 安装及版本库介绍

安装Git 最早Git是在Linux上开发的&#xff0c;很长一段时间内&#xff0c;Git也只能在Linux和Unix系统上跑。不过&#xff0c;慢慢地有人把它移植到了Windows上。现在&#xff0c;Git可以在Linux、Unix、Mac和Windows这几大平台上正常运行了。 在Linux上安装Git 首先&#xff…

python基础:迭代器、生成器(yield)详细解读

1. 迭代器 迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问&#xff0c;知道所有的元素被访问完结束。迭代器只能往前不会后退&#xff0c;不过这也没什么&#xff0c;因为人们很少在迭代途中往后退。 1.1 使用迭代器的优点 对于原生支持随机访问的数据…

LazyInitializationException的四种解决方案–第2部分

本文从教程​​的第1部分继续。 使用PersistenceContextType.EXTENDED的有状态EJB加载收集 该方法只能应用于与Full JEE环境兼容的应用程序&#xff1a;将EJB与PersistenceContextType.EXTENDED一起使用。 检查下面的代码&#xff0c;DAO的样子&#xff1a; package com.ejb…

Linux将硬盘转化为pv,Linux扩展硬盘 物理卷(PV) 卷组(VG) 逻辑卷(LV)

1、给虚拟机添加两块新的sata虚拟硬盘&#xff0c;容量8G和10G# fdisk -l 命令2、分别在这两个硬盘上建立pvPvcreate /dev/sdb 创建一个物理卷/dev/sdb 磁盘名是 fdisk -l 查询出来的Pvscan 查看当前所有物理卷Pvdisplay 查看当前所有物理卷的详情3、创建VG&#xff0c;使得…

ubuntu 16.10 shu rufa meiy ou l e geng xi zhi hou

转载于:https://www.cnblogs.com/ganmk--jy/p/6035894.html

ZOJ Monthly, November 2012

A.ZOJ 3666 Alice and Bob 组合博弈&#xff0c;SG函数应用#include<vector> #include<cstdio> #include<cstring> #include<algorithm>using namespace std;const int maxn 10000 100; int SG[maxn]; vector<int> g[maxn];int mex(int u) { /…

使用Aspect和Spring Profile进行电子邮件过滤

在Web应用程序开发期间&#xff0c;经常需要发送电子邮件。 但是&#xff0c;有时数据库中会包含来自生产的数据&#xff0c;并且存在在电子邮件测试执行期间向真实客户发送电子邮件的风险。 这篇文章将解释如何避免在没有在发送电子邮件功能中明确编写代码的情况下避免这种情…