认识原型模式  

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

 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. django orm 基于双下划线的跨表查询

    一..基于双下划线的跨表查询(join实现) key:正向查询按字段,反向查询按表明小写 1.一对多跨表查询 查询在跨表中可以有两种方式,正向查询就是关键字段在你要搜索的表,没有关键字段就是反向查询 ...

  2. Oracle存储过程常用语法及其使用

    1.什么是存储过程 存储过程Procedure是一组为了完成特定功能的SQL语句集合,经编译后存储在数据库中,用户通过指定存储过程的名称并给出参数来执行.它可以接受参数.输出参数,并可以返回单个或多个 ...

  3. mysql数据库锁的机制-one

    锁概念 : 当高并发访问同一个资源时,可能会导致数据不一致,需要一种机制将用户访问数据的顺序进行规范化,以保证数据库数据的一致性.锁就是其中的一种机制. 举例 :以买火车票为例,火车票可面向广大消费者 ...

  4. Pandas | 15 窗口函数

    为了处理数字数据,Pandas提供了几个变体,如滚动,展开和指数移动窗口统计的权重. 其中包括总和,均值,中位数,方差,协方差,相关性等.本章讨论的是在DataFrame对象上应用这些方法. .rol ...

  5. Python 和 Flask 设计 RESTful API

    #!flask/bin/python from flask import Flask, jsonify from flask import make_response app = Flask(__na ...

  6. R语言参数传递 按引用传递

    R 语言的参数传递是按照引用传递的,二者共享内存 如果想要按值传递 使用函数 copy()

  7. java web开发入门三(Hibernate)基于intellig idea

    Hibernate 1.开发流程 项目配置好后的结构: 1.下载源码: 版本:hibernate-distribution-3.6.0.Final 2.引入hibernate需要的开发包(3.6版本) ...

  8. Java集合详解4:一文读懂HashMap和HashTable的区别以及常见面试题

    <Java集合详解系列>是我在完成夯实Java基础篇的系列博客后准备开始写的新系列. 这些文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查 ...

  9. button 在chrome浏览器下被点击时会出现一个橙色的边框

    问题描述: button在chrome浏览器下被点击时会出现一个橙色的边框 在button上添加 :focus{outline:none;}也无法解决. 解决办法: 在button上添加 :focus ...

  10. selenium爬虫入门(selenium+Java+chrome)

    selenium是一个开源的测试化框架,可以直接在浏览器中运行,就像用户直接操作浏览器一样,十分方便.它支持主流的浏览器:chrome,Firefox,IE等,同时它可以使用Java,python,J ...