原型模式(Prototype)(对象、克隆广告邮件)
有些对象创建过程较为复杂,而且有些时候需要频繁的创建,原型模式通过给出一个原型对象来指明所要创建的对象的类型,然后复制这个原型对象的方法创建更多同类型的对象。这就是原型模式的动机。
原型模式的主要思想是基于现有对象克隆一个新的对象出来,一般是有对象的内部提供克隆的方法,通过该方法返回一个对象的副本。在以下几个场景中,使用原型模式会更简单效率也更高。
(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)(对象、克隆广告邮件)的更多相关文章
- 设计模式系列之原型模式(Prototype Pattern)——对象的克隆
说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...
- Net设计模式实例之原型模式( Prototype Pattern)
一.原型模式简介(Brief Introduction) 原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象. Specify the kin ...
- [工作中的设计模式]原型模式prototype
一.模式解析 提起prototype,最近看多了js相关的内容,第一印象首先是js的原型 var Person=function(name){ this.name=name; } Person.pro ...
- 二十四种设计模式:原型模式(Prototype Pattern)
原型模式(Prototype Pattern) 介绍用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象.示例有一个Message实体类,现在要克隆它. MessageModel usin ...
- 设计模式(四)原型模式Prototype(创建型)
设计模式(四)原型模式Prototype(创建型) 1. 概述 我们都知道,创建型模式一般是用来创建一个新的对象,然后我们使用这个对象完成一些对象的操作,我们通过原型模式可以快速的创建一个对象 ...
- 乐在其中设计模式(C#) - 原型模式(Prototype Pattern)
原文:乐在其中设计模式(C#) - 原型模式(Prototype Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 原型模式(Prototype Pattern) 作者:weba ...
- 原型模式-Prototype(Java实现)
原型模式-Prototype 通过复制(克隆.拷贝)一个指定类型的对象来创建更多同类型的对象. 就像去蛋糕店买蛋糕一样. 柜台里的蛋糕都是非卖品. 只是为顾客提供一种参照. 当顾客看上某一个样式的蛋糕 ...
- 原型模式 prototype 创建型 设计模式(七)
原型模式 prototype 意图 用原型实例指定需要创建的对象的类型,然后使用复制这个原型对象的方法创建出更多同类型的对象 显然,原型模式就是给出一个对象,然后克隆一个或者更多个对象 小时候看 ...
- PHP设计模式 原型模式(Prototype)
定义 和工厂模式类似,用来创建对象.但实现机制不同,原型模式是先创建一个对象,采用clone的方式进行新对象的创建. 场景 大对象的创建. 优点 1.可以在运行时刻增加和删除产品 2.可以改变值或结构 ...
随机推荐
- Han Xin and His Troops(扩展中国剩余定理 Python版)
Han Xin and His Troops(扩展中国剩余定理 Python版) 题目来源:2019牛客暑期多校训练营(第十场) D - Han Xin and His Troops 题意: 看标 ...
- 根据Cron表达式,通过Spring自带的CronSequenceGenerator类获取下次执行时间
Cron表达式通常用于执行一些定时任务,在本篇文章中,暂时不会记录如何根据Cron表达式来执行一些定时任务.本章主要的目的是根据Cron表达式,通过Spring自带的CronSequenceGener ...
- PAT甲级——A1134 Vertex Cover【25】
A vertex cover of a graph is a set of vertices such that each edge of the graph is incident to at le ...
- [AHOI2014/JSOI2014]骑士游戏
题目 思博贪心题写了一个半小时没救了,我也没看出这是一个\(spfa\)来啊 设\(dp_i\)表示彻底干掉第\(i\)只怪物的最小花费,一个非常显然的事情,就是对于\(k_i\)值最小的怪物满足\( ...
- 数组,List,Set相互转化
1.数组转化为List: String[] strArray= new String[]{"Tom", "Bob", "Jane"}; Li ...
- C++之memset函数
可参考: C++中memset函数的用法 C++中memset函数的用法 C++中memset()函数的用法详解 c/c++学习系列之memset()函数 透彻分析C/C++中memset函数 mem ...
- 笔试中sizeof求字节数的问题
1. ]) { cout<<sizeof(ch)<<endl; //或者sizeof(ch)=?; } 这种情况,数组名作为形参,退化成指针,所以sizeof结果是4(32位编 ...
- 软件-版本控制器-VisualSVN:VisualSVN
ylbtech-软件-版本控制器-VisualSVN:VisualSVN VisualSVN 1.返回顶部 2.返回顶部 3.返回顶部 4.返回顶部 5.返回顶部 0. https:/ ...
- 使用Java代码获取Java进程ID的方法
需要jre/lib下的tools.jar包 public class Test { public static void main(String[] args) throws Exception { ...
- https证书加密
对称加密 浏览器向服务端发送请求时,服务端首先给浏览器发送一个秘钥,浏览器用秘钥对传输的数据进行加密后发送给浏览器,浏览器拿到加密后的数据使用秘钥进行解密 非对称加密 服务端通过rsa算法生成一个公钥 ...