认识原型模式  

  原型模式是比较简单的设计模式。废话不多说,直接看定义:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。通过实例指定种类,种类就是初始化的类,然后通过拷贝创建对象。先展示一个实现的原型模式的例子

 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)的更多相关文章

  1. Net设计模式实例之原型模式( Prototype Pattern)

    一.原型模式简介(Brief Introduction) 原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象. Specify the kin ...

  2. 设计模式系列之原型模式(Prototype Pattern)——对象的克隆

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  3. 设计模式学习心得<原型模式 Prototype >

    原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这种模式是实现了一个原型接口,该接口用于创建当 ...

  4. IOS设计模式浅析之原型模式(Prototype)

    原型模式的定义 “使用原型实例指定创建对象的种类,并通过复制这个原型创建新的对象”.最初的定义出现于<设计模式>(Addison-Wesley,1994). 简单来理解就是根据这个原型创建 ...

  5. 《JAVA设计模式》之原型模式(Prototype)

    在阎宏博士的<JAVA与模式>一书中开头是这样描述原型(Prototype)模式的: 原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办 ...

  6. 设计模式入门之原型模式Prototype

    //原型模式:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象 //简单来说,当进行面向接口编程时,假设须要复制这一接口对象时.因为不知道他的详细类型并且不能实例化一个接口 //这时就须要 ...

  7. [工作中的设计模式]原型模式prototype

    一.模式解析 提起prototype,最近看多了js相关的内容,第一印象首先是js的原型 var Person=function(name){ this.name=name; } Person.pro ...

  8. 设计模式(四)原型模式Prototype(创建型)

      设计模式(四)原型模式Prototype(创建型) 1.   概述 我们都知道,创建型模式一般是用来创建一个新的对象,然后我们使用这个对象完成一些对象的操作,我们通过原型模式可以快速的创建一个对象 ...

  9. 乐在其中设计模式(C#) - 原型模式(Prototype Pattern)

    原文:乐在其中设计模式(C#) - 原型模式(Prototype Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 原型模式(Prototype Pattern) 作者:weba ...

  10. PHP设计模式 原型模式(Prototype)

    定义 和工厂模式类似,用来创建对象.但实现机制不同,原型模式是先创建一个对象,采用clone的方式进行新对象的创建. 场景 大对象的创建. 优点 1.可以在运行时刻增加和删除产品 2.可以改变值或结构 ...

随机推荐

  1. xampp1.8.3 配置 php5.x 访问 SQL Server 2008

    1.安装xampp 2.下载php sqlsrv扩展 Microsoft Drivers 3.2 for PHP for SQL Server 官方下载地址: http://www.microsoft ...

  2. RF元素定位的例子

    Execute Javascript $("input[type='button']").click() Comment Click Button css=input.login_ ...

  3. NOIP 2002 选数

    洛谷 P1036 选数 洛谷传送门 JDOJ 1297: [NOIP2002]选数 T2 JDOJ传送门 Description ​ 已知 n 个整数 x1,x2,-,xn,以及一个整数 k(k< ...

  4. java.lang.IllegalArgumentException: Invalid character found in the request target. The valid charact

    线上环境中部署的 Tomcat 项目,出现部分页面无法打开的情况,但本地环境是好的.经过排查发现,本地 Tomcat版本为 7.0.77,而线上版本为 7.0.88.报错的具体描述为java.lang ...

  5. python基础之八:知识小结及补充

    一.python2 与python3 的区别 1.在2中print后可带扣号,也可不带,3中必须带,否则报错! #print 'hello python2' print('hello python3' ...

  6. 转:ubuntu16安装python3.6并将环境设置为系统默认

    按照本文升级到3.6,但pip无法运行了,问题没有解决 1.添加python3.6安装包,并且安装 sudo apt-get install software-properties-common su ...

  7. yugabyte 安装pg_hashids 扩展

    主要目的比较简单,就是测试下yugabyte 对于pg 扩展的支持,今天在测试plv8的时候发现有问题(以及提交issue了,很期待官方的解决) 所以测试下一个其他的扩展,看看是否像官方介绍的那样 环 ...

  8. Certification information不能过大

    /* If certification information is too big this event can't be transmitted as it would cause failure ...

  9. gcc O2优化选项对内嵌汇编以及函数递归调用的影响

    学习和使用c这些年来,很多方面都未深入研究过,就如脱离了IDE后,我可能连编译一个c文件的命令都写不出来. 最近需要在c中内嵌汇编解决问题,参考网上相关的资料写了一段汇编代码,在测试的时候时好时坏,找 ...

  10. Python 中如何判断 list 中是否包含某个元素

    在python中判断 list 中是否包含某个元素: ——可以通过in和not in关键字来判读 例如: abcList=['a','b','c',1,2,3] if 'a' in abcList: ...