有些对象创建过程较为复杂,而且有些时候需要频繁的创建,原型模式通过给出一个原型对象来指明所要创建的对象的类型,然后复制这个原型对象的方法创建更多同类型的对象。这就是原型模式的动机。

原型模式的主要思想是基于现有对象克隆一个新的对象出来,一般是有对象的内部提供克隆的方法,通过该方法返回一个对象的副本。在以下几个场景中,使用原型模式会更简单效率也更高。

(1)当一个系统应该独立于它的产品创建、构成和表示时,要使用原型模式。

(2)当要实例化的类是在运行时刻指定时,例如:动态装载。

(3)为了避免创建一个与产品类层次平行的类层次时。

(4)当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆他们可能比每次用合适的状态手工实例化该类更方便一些(也就是当我们在处理一些比较简单的对象,并且对象之间的区别很小,可能只是很固定的几个属性不同的时候,使用原型模式更合适)。

原型模式主要用于对象的复制,它的核心是原型类Prototype。Prototype类需要具备以下两个条件:

(1)实现Cloneable接口: JAVA语言中有一个Cloneable接口,他的作用只用一个,就是在运行时通知虚拟机可以安全的在实现了此接口的类上使用clone方法。在java虚拟机中,只有实现了这个接口的类才可以被复制,否则会抛出异常CloneNotSupportedExceotion

(2)重写Object类中的clone方法。clone()作用是返回对象的一个复制,但其作用域是protected类型的,一般的类无法调用,因此,Prototype类需要将clone方法作用域改为public。

原型模式实现广告模板克隆:

广告模板:

 public class Adv {
private String subject;
private String contxt; public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getContxt() {
return contxt;
}
public void setContxt(String contxt) {
this.contxt = contxt;
} }

mail类 实现可对自身进行克隆:

 /*
* 实现Cloneable 接口 可以对自身进行克隆
*/
public class Mail implements Cloneable{
private String recrviver = "AAA";
private String subject = "BBB";
private String appellation = "CCC";
private String tail = "DDD";
private String contxt = "EEE"; public Mail() {
super();
}
public Mail(Adv adv) {
contxt = adv.getContxt();
subject = adv.getSubject();
}
@Override
public Mail clone() {
Mail mail = null;
try { //为什么我们在派生类中覆盖Object的clone()方法时,一定要调用super.clone()呢?在运行时刻,Object中的clone()识别出你要复制的是哪一个对象
// 然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中
mail= (Mail) super.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return mail;
} @Override
public String toString() {
return "Mail [recrviver=" + recrviver + ", subject=" + subject + ", appellation=" + appellation + ", tail=" + tail
+ ", contxt=" + contxt + "]";
}
public String getRecrviver() {
return recrviver;
}
public void setRecrviver(String recrviver) {
this.recrviver = recrviver;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getAppellation() {
return appellation;
}
public void setAppellation(String appellation) {
this.appellation = appellation;
}
public String getTail() {
return tail;
}
public void setTail(String tail) {
this.tail = tail;
}
public String getContxt() {
return contxt;
}
public void setContxt(String contxt) {
this.contxt = contxt;
} }

测试类:

 public class Test {

     public static void main(String[] args) {
// Mail m1 = new Mail();
// Mail m2 = m1.clone();
// System.out.println( m2.toString()); Mail mail= new Mail(new Adv());//Adv是广告的模板
for(int i = 0; i<5;i++){
Mail m = mail.clone();//克隆原型邮件
m.setRecrviver(""+i);//向邮件中添加不同的收件信息
System.out.println(m.toString()); } } }
 Mail [recrviver=0, subject=null, appellation=CCC, tail=DDD, contxt=null]
Mail [recrviver=1, subject=null, appellation=CCC, tail=DDD, contxt=null]
Mail [recrviver=2, subject=null, appellation=CCC, tail=DDD, contxt=null]
Mail [recrviver=3, subject=null, appellation=CCC, tail=DDD, contxt=null]
Mail [recrviver=4, subject=null, appellation=CCC, tail=DDD, contxt=null]

⑴浅复制(浅克隆)

被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象内存储的引用,而不复制它所引用的对象。

⑵深复制(深克隆)

被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。

从以下我们可以看出,clone所进行的时浅克隆们m2只复制了m1所存储的引用当我们对m2做出更改时m1也会改变:

     public static void main(String[] args) {

        Mail m1 = new Mail();
Mail m2 = m1.clone();
System.out.println( m2.toString()); System.out.println(m1.equals(m2));
System.out.println(m1.getAppellation().equals(m2.getAppellation())); // Mail mail= new Mail(new Adv());//Adv是广告的模板
// for(int i = 0; i<5;i++){
// Mail m = mail.clone();//克隆原型邮件
// m.setRecrviver(""+i);//向邮件中添加不同的收件信息
// System.out.println(m.toString());
//
// } } }

Mail [recrviver=AAA, subject=BBB, appellation=CCC, tail=DDD, contxt=EEE] false true

实现深克隆时需要编写的代码会比较复杂,当对象的嵌套结构复杂时由于要实现深克隆,每一层的类都必须支持深克隆。实现起来会比较复杂。

(1)使用原型模式复制不会调用类的构造方法,因为对象的复制是通过调用object类的clone方法来完成的,它直接在内存中复制数据,因此不会调用到类的构造方法,

(2)构造方法中的代码不会执行,甚至脸访问权限都对原型模式无效,所以单例模式与原型模式是冲突的。

原型模式(Prototype)(对象、克隆广告邮件)的更多相关文章

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

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

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

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

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

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

  4. 二十四种设计模式:原型模式(Prototype Pattern)

    原型模式(Prototype Pattern) 介绍用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象.示例有一个Message实体类,现在要克隆它. MessageModel usin ...

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

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

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

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

  7. 原型模式-Prototype(Java实现)

    原型模式-Prototype 通过复制(克隆.拷贝)一个指定类型的对象来创建更多同类型的对象. 就像去蛋糕店买蛋糕一样. 柜台里的蛋糕都是非卖品. 只是为顾客提供一种参照. 当顾客看上某一个样式的蛋糕 ...

  8. 原型模式 prototype 创建型 设计模式(七)

    原型模式  prototype 意图 用原型实例指定需要创建的对象的类型,然后使用复制这个原型对象的方法创建出更多同类型的对象   显然,原型模式就是给出一个对象,然后克隆一个或者更多个对象 小时候看 ...

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

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

随机推荐

  1. Mybatis功能架构及执行流程

    原文地址:http://blog.51cto.com/12222886/2052647 一.功能架构设计 功能架构讲解: 我们把Mybatis的功能架构分为三层: (1) API接口层:提供给外部使用 ...

  2. CCPC 2019 网络赛 HDU huntian oy (杜教筛)

    1005 huntian oy (HDU 6706) 题意: 令,有T次询问,求 f(n, a, b). 其中 T = 10^4,1 <= n,a,b <= 1e9,保证每次 a,b互质. ...

  3. Tomcat点击项目名称,加载一个action请求

    <meta http-equiv="refresh" content="0;url=index.action">

  4. 安装MySql社区版(35-3)

    1,https://dev.mysql.com/ --------------------------------------------------------------------------- ...

  5. 一次完整的HTTP请求与响应涉及哪些知识?

    Java技术栈 www.javastack.cn 优秀的Java技术公众号 作者:Ruheng 地址:http://www.jianshu.com/p/c1d6a294d3c0 本文以HTTP请求和响 ...

  6. 4_4.springboot之Web开发登录和拦截器

    1.登录处理 1).禁用模板引擎的缓存 # 禁用缓存 spring.thymeleaf.cache=false 2).页面修改完用ctrl+f9:重新编译: LoginController @Cont ...

  7. 测试环境添加spark parcel 2.1步骤

    1.先到http://archive.cloudera.com/spark2/parcels/2.1.0.cloudera1/ 下载需要的文件比如我linux版本需要是6的 hadoop6需要下载这些 ...

  8. iOS逆向系列-逆向APP思路

    界面分析 通过Cycript.Reveal. 对于Reveal安装配置可参考配置iOS逆向系列-Reveal 通过Reveal找到内存中的UI对象 静态分析 开发者编写的所有代码最终编译链接到Mach ...

  9. 【左偏树】[LuoguP1456] Monkey King

    多...多组数据... awsl 死命的MLE,原来是忘记清空数组了.... 左偏树模板? 对于每一个操作,我们把两个节点$x,y$的祖先$fx,fy$找到,然后把他们的左右儿子分别合并 最后把$v[ ...

  10. pixi.js 学习

     事件(event):PIXI库在精灵和舞台上提供了事件,用于交互. stage.click = function(data){ var event = data.originalEvent } sp ...