秒懂设计模式——原型模式
(五)原型模式
【官方定义】用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象,属于对象创建模式。
【举例】在找工作的时候,通常需要我们的毕业证和学位证,但是我们一般不会把原件(原型实例)给到用人单位,而是会把原件复印(拷贝)几份,然后供用人单位使用。
【Java代码】
①创建一个证书抽象类。
package com.liyan.prototype;
/**
* 证书抽象类
* <p>Title: Certificate</p>
* @author Liyan
* @date 2017年5月2日 下午3:17:37
*/
public abstract class Certificate implements Cloneable{
/**证书编号*/
private Integer id;
/**证书名称*/
protected String name;
/**测试方法*/
abstract void testMethod();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Certificate [id=" + id + ", name=" + name + "]";
}
}
②创建证书扩展类——毕业证
package com.liyan.prototype;
/**
* 数据信息扩展类——毕业证
* <p>Title: GraduationCertificate</p>
* @author Liyan
* @date 2017年5月2日 下午3:17:47
*/
public class GraduationCertificate extends Certificate{
public GraduationCertificate() {
name = "毕业证";
}
@Override
void testMethod() {
System.out.println("毕业证复印完成!");
}
}
③创建证书扩展类——学位证
package com.liyan.prototype;
/**
* 证书扩展类——学位证
* <p>Title: DegreeCertificate</p>
* @author Liyan
* @date 2017年5月2日 下午3:18:26
*/
public class DegreeCertificate extends Certificate{
public DegreeCertificate() {
name = "学位证";
}
@Override
void testMethod() {
System.out.println("学位证复印完成!");
}
}
④创建原型模式管理器——证书管理器
package com.liyan.prototype;
import java.util.HashMap;
/**
* 原型模式管理器——证书管理器
* <p>Title: CertificateManger</p>
* @author Liyan
* @date 2017年5月2日 下午3:24:40
*/
public class CertificateManger {
//证书的map集合
private static HashMap<Integer, Certificate> certificateMap = new HashMap<Integer, Certificate>(0);
//私有构造方法
private CertificateManger (){}
//懒加载构建原型模式管理器的单例模式
private static CertificateManger certificateManger = null;
/**
* 获取单例模式的原型模式管理器
* <p>Title: getCertificateManger</p>
* @author Liyan
* @date 2017年5月2日 下午3:24:51
* @return CertificateManger
*/
public static CertificateManger getCertificateManger() {
if (certificateManger == null) {
certificateManger = new CertificateManger();
}
return certificateManger;
}
/**
* 加载缓存
* <p>Title: getLoad</p>
* @author Liyan
* @date 2017年5月2日 下午3:25:07
*/
public static void getLoad() {
GraduationCertificate certificate1 = new GraduationCertificate();
certificateMap.put(1, certificate1);
DegreeCertificate certificate2 = new DegreeCertificate();
certificateMap.put(2, certificate2);
}
/**
* 根据key获取克隆后的对象
* <p>Title: getCertificate</p>
* @author Liyan
* @date 2017年5月2日 下午3:25:31
* @param key
* @return Certificate
*/
public static Certificate getCertificate(Integer key) {
try {
Certificate certificate = (Certificate) certificateMap.get(key);
if (certificate != null) {
Certificate datinfo = (Certificate) certificate.clone();
System.out.println("key="+key+"的对象克隆完成,datinfo="+datinfo);
return datinfo;
}else {
System.out.println("key="+key+"并未加载!");
return null;
}
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
⑤测试
package com.liyan.prototype;
/**
* 测试
* <p>Title: Test</p>
* @author Liyan
* @date 2017年5月2日 下午3:30:21
*/
public class Test {
@SuppressWarnings("static-access")
public static void main(String[] args) {
//提前加载到缓存数据
CertificateManger.getLoad();
//获取单例类CertificateManger
CertificateManger manger = CertificateManger.getCertificateManger();
//获取毕业证复印件
Certificate certificate1 = manger.getCertificate(1);
certificate1.testMethod();
//获取学位证复印件
Certificate certificate2 = manger.getCertificate(2);
certificate2.testMethod();
}
}
⑥测试结果
key=1的对象克隆完成,datinfo=Certificate [id=null, name=毕业证]
毕业证复印完成!
key=2的对象克隆完成,datinfo=Certificate [id=null, name=学位证]
学位证复印完成!
图解关系:
分析:
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。
独特的优点:
(1)性能比直接new一个对象要好的多。因为clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显,所以在需要重复地创建相似对象时可以考虑使用原型模式。
(2)原型模式创建模式不会损坏原有对象。
(3)工厂模式对新产品的适应能力比较弱,层级结构比较复杂,没有原型模式简洁。
注意事项:
(1)使用原型模式复制对象不会调用类的构造方法。因为clone方法,会直接在内存中复制数据。
(2)单例模式与原型模式是冲突的。因为clone方法直接无视构造方法的权限。