设计模式之(六)原型模式(ProtoType)
认识原型模式
原型模式是比较简单的设计模式。废话不多说,直接看定义:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。通过实例指定种类,种类就是初始化的类,然后通过拷贝创建对象。先展示一个实现的原型模式的例子
public class Product {
private String proID;
private String proName;
private String proDescption;
public String getProID() {
return proID;
}
public void setProID(String proID) {
this.proID = proID;
}
public String getProName() {
return proName;
}
public void setProName(String proName) {
this.proName = proName;
}
public String getProDescption() {
return proDescption;
}
public void setProDescption(String proDescption) {
this.proDescption = proDescption;
}
public void showPro(){
System.out.println("ID:"+this.getProID()+";Name:"+this.getProName()+";Descrip:"+this.getProDescption());
System.out.println("-------------------------------------");
}
//关键方法
public Product cloneself(){
Product p = new Product();
p.setProName(this.proID);
p.setProID(this.proID);
p.setProDescption(this.proDescption);
return p;
}
}
public class Client {
public static void main(String[] args) {
Product pp = new Product();
pp.setProID("P0001");
pp.setProName("玩具一号");
pp.setProDescption("此为玩具一号的初代产品");
pp.showPro();
//拷贝
Product pp2 = pp.cloneself();
pp2.showPro();
pp2.setProDescption("此为玩具一号的升级产品");
pp2.showPro();
//原来的
pp.showPro();
}
}
//实行效果
ID:P0001;Name:玩具一号;Descrip:此为玩具一号的初代产品
-------------------------------------
ID:P0001;Name:P0001;Descrip:此为玩具一号的初代产品
-------------------------------------
ID:P0001;Name:P0001;Descrip:此为玩具一号的升级产品
-------------------------------------
ID:P0001;Name:玩具一号;Descrip:此为玩具一号的初代产品
-------------------------------------
通过例子可以看出来,原型模式的核心就是克隆自己的方法,在例子中就是 cloneself,实例对象调用的 cloneself ,就识别出来了对象是哪个类的。同时拷贝了一个新的对象,和原来的实例是完全分离的两个实例。这样实现的原型模式 和 new 比起来有诸多优势,
1)通过拷贝创建对象时,不用关心实例来自哪个类型,只要在例子中实现了拷贝自己的方法即可。
2)通过 new 新建对象时,每个值都是初始状态的,对各个属性,还需要赋值处理。而原型模式在新建了对象时候,就直接获取了原来对象的值,如果有个别属性不一样修改了即可。
通过上面那种方式实现的原型模式,只是在编程方面更灵活。编程效率更高而已,对于执行效果而言,和不用效果是一样的。因为这样实现的模式也是通过new来创建的。有没有更好的克隆方式呢,java 语言里面是有这样的方式的。接下来就介绍 java 实现的 clone 方式。
public class ProtoType implements Cloneable {
//......属性值省略
@Override
public ProtoType clone(){
ProtoType pro = null;
try{
pro = (ProtoType)super.clone();
}
catch(CloneNotSupportedException ex){
ex.printStackTrace();
}
return pro;
}
}
上面的代码就是用 java 自己的 clone 实现的克隆。方式就是在 Object 里面有一个 clone 方法,就是用来拷贝对象的,只是使用这个函数需要实现 Cloneable 接口,然后再重写这个方法。为了更好的理解 clone 用法,我们来改造上面的例子。通过 java 语言提供的 clone 来完成这个例子。只是把关键代码贴出来,就是把 原来例子中的 cloneself() 替换成 clone() 。
用 java 自带 clone 改造例子
public class Product implements Cloneable {
private String proID;
private String proName;
private String proDescption;
public String getProID() {
return proID;
}
public void setProID(String proID) {
this.proID = proID;
}
public String getProName() {
return proName;
}
public void setProName(String proName) {
this.proName = proName;
}
public String getProDescption() {
return proDescption;
}
public void setProDescption(String proDescption) {
this.proDescption = proDescption;
}
public void showPro(){
System.out.println("ID:"+this.getProID()+";Name:"+this.getProName()+";Descrip:"+this.getProDescption());
System.out.println("-------------------------------------");
}
//关键方法
// public Product cloneself(){
// Product p = new Product();
// p.setProName(this.proID);
// p.setProID(this.proID);
// p.setProDescption(this.proDescption);
//
// return p;
// }
//关键方法
@Override
public Product clone(){
Product pro = null;
try{
pro = (Product)super.clone();
}
catch(CloneNotSupportedException ex){
ex.printStackTrace();
}
return pro;
}
}
通过 java 语言提供的 clone 方法来复制效率很高,主要有一下原因:
1)不用执行构造函数。
2)原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。
浅拷贝和深拷贝
浅拷贝:就是只拷贝基本类型的值,比如 int、String 等类型。(这里把 String 类型当成了基本类型)。
深拷贝:除了浅拷贝的值外,还需要拷贝引用类型的对象。
public class Product2 implements Cloneable {
private String name;
private ArrayList<String> list = new ArrayList<String>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ArrayList<String> getList() {
return list;
}
public void setList(String str) {
this.list.add(str);
}
@Override
public Product2 clone(){
Product2 pro = null;
try{
pro = (Product2)super.clone();
}
catch(CloneNotSupportedException ex){
ex.printStackTrace();
}
return pro;
}
public void show(){
System.out.println("name="+this.name+" list="+this.list);
}
}
public class Client {
public static void main(String[] args) {
Product2 pp = new Product2();
pp.setName("pro2");
pp.setList("pwq");
pp.show();
Product2 pp2 = pp.clone();
pp2.setName("pro222");
pp2.setList("pcf");
pp2.show();
}
}
/*****执行效果**********/
name=pro2 list=[pwq]
name=pro222 list=[pwq, pcf]
比较两次的执行效果,克隆后的类名字是分离了,就是成功克隆了;但是 list 这个很明显就是共享了,就是没有克隆成功。这个就是浅克隆。如果需要深克隆,就需要修改下上面代码;
@SuppressWarnings("unchecked")
@Override
public Product2 clone(){
Product2 pro = null;
try{
pro = (Product2)super.clone();
pro.list = (ArrayList<String>)pro.list.clone();
}
catch(CloneNotSupportedException ex){
ex.printStackTrace();
}
return pro;
}
加上这句话后,修改为深度拷贝。手动编写的类也是典型的引用类型,深拷贝也是需要重点注意的。
原型管理器
有时候原型可能有多个,而且还不固定,中间可能动态的变化。这个时候对原型的管理就需要维护一个注册表,这个注册表就是原型管理器。在原型注册器中可以添加和销毁。看例子理解
public interface ProtoType {
public String getName();
public void setName(String name);
public ProtoType clone();
}
public class ConcreteProtoTypeA implements ProtoType{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public ProtoType clone(){
ConcreteProtoTypeA cA = new ConcreteProtoTypeA();
cA.setName(this.name);
return cA;
}
}
public class ConcreteProtoTypeB implements ProtoType{
//..........
}
//原型管理器
public class ProtoTypeManager {
private static Map<String,ProtoType> pt = new HashMap<String,ProtoType>();
//不让实例化
private ProtoTypeManager(){}
public static synchronized void setProtoType(String protoID,ProtoType p){
pt.put(protoID, p);
}
public static synchronized void removeProtoType(String protoID){
pt.remove(protoID);
}
public static synchronized ProtoType getProtoType(String protoID){
ProtoType p = null;
if(pt.containsKey(protoID)){
p = pt.get(protoID);
}
return p;
}
public static void show(){
System.out.println(pt);
}
}
原型管理器
通过这个例子就很清楚的理解了原型管理器是有什么用处了,本质上就是存放多个原型的,并且能够动态的添加、删除、获取。
使用场景
1、需要一个类实例化大量的重复对象,或者数据重复性很大,极个别需要修改的属性。
2、对象初始化过程比较复杂。
3、在运行时刻不方便获取原型的类时,也可以通过原型模式来实现。
小结
原型模式说了这么多,本质就是原型不需要获取到所属种类,通过原型就能够通过克隆自己来创建对象。通过这个本质就能看到引出的优势。而 java 又对这个模式进行了语言级别的支持。Object 的 clone 就能够克隆,只要实现了 cloneable 接口。java 自带的 clone 克隆自己还不需要再次执行构造方法,操作的是内存二进制数据,效率非常的好。
设计模式之(六)原型模式(ProtoType)的更多相关文章
- Net设计模式实例之原型模式( Prototype Pattern)
一.原型模式简介(Brief Introduction) 原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象. Specify the kin ...
- 设计模式系列之原型模式(Prototype Pattern)——对象的克隆
说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...
- 设计模式学习心得<原型模式 Prototype >
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这种模式是实现了一个原型接口,该接口用于创建当 ...
- IOS设计模式浅析之原型模式(Prototype)
原型模式的定义 “使用原型实例指定创建对象的种类,并通过复制这个原型创建新的对象”.最初的定义出现于<设计模式>(Addison-Wesley,1994). 简单来理解就是根据这个原型创建 ...
- 《JAVA设计模式》之原型模式(Prototype)
在阎宏博士的<JAVA与模式>一书中开头是这样描述原型(Prototype)模式的: 原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办 ...
- 设计模式入门之原型模式Prototype
//原型模式:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象 //简单来说,当进行面向接口编程时,假设须要复制这一接口对象时.因为不知道他的详细类型并且不能实例化一个接口 //这时就须要 ...
- [工作中的设计模式]原型模式prototype
一.模式解析 提起prototype,最近看多了js相关的内容,第一印象首先是js的原型 var Person=function(name){ this.name=name; } Person.pro ...
- 设计模式(四)原型模式Prototype(创建型)
设计模式(四)原型模式Prototype(创建型) 1. 概述 我们都知道,创建型模式一般是用来创建一个新的对象,然后我们使用这个对象完成一些对象的操作,我们通过原型模式可以快速的创建一个对象 ...
- 乐在其中设计模式(C#) - 原型模式(Prototype Pattern)
原文:乐在其中设计模式(C#) - 原型模式(Prototype Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 原型模式(Prototype Pattern) 作者:weba ...
- PHP设计模式 原型模式(Prototype)
定义 和工厂模式类似,用来创建对象.但实现机制不同,原型模式是先创建一个对象,采用clone的方式进行新对象的创建. 场景 大对象的创建. 优点 1.可以在运行时刻增加和删除产品 2.可以改变值或结构 ...
随机推荐
- l获取list 的长度,EL表达式获取list的长度,EL表达式获取list大小
在jsp页面中不能通过${list.size}取列表长度,而是 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" pref ...
- 用 tomcat 部署 Jenkins
在tomcat 下面部署 Jenkins 版本 tomcat (7.0.94) + jdk (7) + jenkins (2.46.3) 前两次没有部署成功,应该是 jdk 版本的问题, 如果不成功 ...
- testlink 1.9.13之后版本,将动作默认显示
最近升级了testlink,从低版本升级到1.9.14,而作为用户来说,改变了用户习惯,感觉不太好,其中有一个用户习惯是,点击某一条用例或测试集时,要点击动作才能显示实际的内容,如下: 每次都点击很不 ...
- 简述 gevent模块的作用和应用场景。
当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成, 再在适当的时候切换回来继续执行.由于IO操作非常耗时,经常使程序处于等待状态, 有了geve ...
- 【java异常】Expected one result (or null) to be returned by selectOne(), but found: 63
OmQuotaTBBean omQuotaTBBean = mOmQuotaTBMapper.findOmQuotaTB(); 改成 List<OmQuotaTBBean> listOmQ ...
- java http get和post请求
1.http工具类 package com.funshion.common.utils; import java.net.URI;import java.net.URL; import org.apa ...
- hadoop exit code 退出码含义
原文传送门:http://www.2cto.com/database/201308/236519.html "OS error code 1: Operation not permitted ...
- bzoj3589 动态树 求链并 容斥
bzoj3589 动态树 链接 bzoj 思路 求链并. 发现只有最多5条链子,可以容斥. 链交求法:链顶是两条链顶深度大的那个,链底是两个链底的\(lca\) 如果链底深度小于链顶,就说明两条链没有 ...
- NOIP2019翻车前写(and 抄)过的代码
咕咕咕.按上传时间升序排列. //树的重心 void dfs(int x) { v[x]=1; size[x]=1; int max_part=0; for(int i=hed[x];i;i=nxt[ ...
- kafka如何保证数据可靠性和数据一致性
数据可靠性 Kafka 作为一个商业级消息中间件,消息可靠性的重要性可想而知.本文从 Producter 往 Broker 发送消息.Topic 分区副本以及 Leader 选举几个角度介绍数据的可靠 ...