秒懂设计模式——原型模式
(五)原型模式
【官方定义】用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象,属于对象创建模式。
【举例】在找工作的时候,通常需要我们的毕业证和学位证,但是我们一般不会把原件(原型实例)给到用人单位,而是会把原件复印(拷贝)几份,然后供用人单位使用。
【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方法直接无视构造方法的权限。