认识原型模式  

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

 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. nginx 请求文件 进行用户认证/鉴权: internal(限制为内部调用)

    在进行WEB开发时, 必然会遇到向用户返回文件的场景(如图片, 文档等等), 当返回的文件较小时, 我们可以直接通过接口以数据流的形式向前台返回, 因为文件较小, 因此也不会太过于影响响应速度及服务器 ...

  2. tomcat 多实例部署

    tomcat 配置多个实例 参考文档 聊聊 Tomcat 的单机多实例 https://www.cnblogs.com/mafly/p/tomcat.html 极客学院 Tomcat 8 权威指南 h ...

  3. hdu2281&&POJ1320——Pell方程

    hdu2281 输入一个 $N$,求最大的 $n$($n \leq N$)和 $x$,使得 $x^2 = \frac{1^2+2^2+...+n^2}{n}$. 分析: 将右边式子的分子求和化简,有: ...

  4. macos -bash: yarn: command not found/-bash: cnpm: command not found

    -bash: cnpm: command not found-bash: yarn: command not found-bash: xxxx: command not found如上yarn/cnp ...

  5. unzip命令(转)

    unzip命令用于解压缩由zip命令压缩的“.zip”压缩包. 语法 unzip(选项)(参数) 选项 -c:将解压缩的结果显示到屏幕上,并对字符做适当的转换: -f:更新现有的文件: -l:显示压缩 ...

  6. Koa帮我们做了什么

    整理web渲染思路,与KOA作比较 1.开启服务器并监听端口,注册监听事件 // 原生 let http = require('http') const server = http.createSer ...

  7. 测试之selenium简介

    目录 selenium是什么? 应该具备的知识 Selenium功能特性 Selenium的局限性 Selenium与QTP比较 Selenium工具套件 Selenium集成开发环境(IDE) Se ...

  8. vue 2.0 及 vue 3.0 rem配置

    vue 2.0 配置 rem 首先先安装postcss-px2rem   (百度可以) https://www.jianshu.com/p/e6476bbc2131 npm install postc ...

  9. 华为鸿蒙OS发布!方舟支持混合编译,终将可替换安卓?

    前言 有关于鸿蒙的消息之前也有说过,就在昨天下午,华为举行了2019开发大会,正式推出了鸿蒙os系统(Harmony).其相关负责人表示,也是基于微软内核的全场景分布式OS   鸿蒙凭借微内核的优势, ...

  10. Linux中文件权限查看和修改

    权限定义 linux文件权限分为:r读权限(4).w写权限(2).x执行权限(1) linux权限对象分为:拥有者.组用户.其他用户 权限修改: chown user:group /usr/local ...