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

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

(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. C#winfrom listview 设置显示图片

    ListView控件有5种显示图片方式:LargeIcon(大图标),Detail(详细),SmallIcon(小图标),List(列表),Tile,常用前4种.  这里说一下设置方式:LargeIc ...

  2. PAT甲级——A1117 Eddington Number【25】

    British astronomer Eddington liked to ride a bike. It is said that in order to show off his skill, h ...

  3. 接着上回,导包正确之后,出现javabean.Friend cannot be cast to java.util.List,的错误。找了很久。以为是User user0作为参数,改成了String username还是错误,看了看listFriend.jsp没有错误,我想会不会是包多了,导致类型复杂。最后发现包少了一个:

    import org.apache.commons.dbutils.handlers.BeanListHandler;这个包,BeanListHandler让我发现List<Friend> ...

  4. UNIT对话系统(杂记)

    单轮对话指标: 召回率=机器人能回答的问题数/问题总数 准确率=机器人正确回答的问题数/问题总数 问题解决率=机器成功解决的问题数/问题总数 多轮对话指标: 任务完成率=成功结束的多轮会话数/多轮会话 ...

  5. ASP.NET WEB API 特性路由

    一.什么是特性路由? 特性路由是指将RouteAttribute或自定义继承自RouteAttribute的特性类标记在控制器或ACTION上,同时指定路由Url字符串,从而实现路由映射,相比之前的通 ...

  6. Android开发 音视频开发需要了解的专业术语知识

    前言 在摸索一段时间的音视频开发后,越来越发现这个坑的深度真是特别的深. 除了了解Android自带的音视频处理API以外,还得了解一些视频与音频方面的知识.这篇博客就是主要讲解这方面的专业术语.内容 ...

  7. MySQL数据库CRUD命令用法

    数据库CRUD操作即添加(Create).读取(Read).更新(Update)和删除(Delete). 1. 添加操作也称插入操作,使用Insert语句,Insert语句可以用于几种情况: 插入完整 ...

  8. 2、java变量+零碎知识点

    1>展示console:window--show view--console2>创建工程 右键--new---java project 文件夹 jre src 所有的java类都在src中 ...

  9. CobaltStrike与Metasploit实战联动

    前言 CobalStrike 与 Metasploit 均是渗透利器,各有所长.前者更适合做稳控平台,后者则更擅长内网各类探测搜集与漏洞利用.两者更需要灵活的联动,各自相互依托,从而提升渗透的效率. ...

  10. 自定义UICollectionViewLayout之CATransform3D

    1.自定义UICollectionViewLayout旋转效果 之前有自定义UICollectionViewLayout(适用于多个section),本文是一个对cell进行CATransform3D ...