原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需知道任何创建的细节。克隆模式对性能有很大的提高,因为每次创建对象的时候,如果我们都是通过new来完成,那么每次都要执行一次构造函数,如果构造函数的执行时间很长,则多次执行这个初始化就显得很低效。一般在初始化的信息不发生变化的情况下,克隆是最好的办法,这既能隐藏对象创建的细节,又对性能有很大的提高。等于是不用重新初始化对象,而是动态地获得对象运行时的状态。
原型模式结构:
Prototype:抽象类,原型类,声明一个克隆自身的接口,
Client:关联原型类 Prototype,让一个原型克隆自身,从而创建一个行的对象,
ConcretePrototype:具体原型类,继承抽象的原型类,实现一个克隆自身的操作。
写这篇文章让我对Java和c#的差别又加深了些,因为在写的过程中有些细节需要对比查资料,还好最后搞定了,主要是我也是在学习的阶段。也许会有人笑话这样也来写文章,但我并不觉得羞愧,因为我早说过了,这是自己的读后感,想到就表达出来。所以很欢迎大神指点其中的不足。
看完书中这一篇之后发现,原型模式核心的内容是 clone() 方法的重写。
这里面涉及到两个核心的概念:浅复制 和 深复制 ,这两种表现出来的结果状态略有不同,关于这个的详细解释,请看这篇文章 详解Java中的clone方法 -- 原型模式,本文按照书中介绍,分别演示浅复制和深复制的效果。嗯,说了好多了。我们直接试试代码。
先来浅复制的实现:
1、新建一个原型类,这是个抽象类:
package abstractprototype; /** * Created by Administrator on 2017/8/4. */ /** * Prototype 实现Cloneable接口,重写接口中的clone()方法 */ public abstract class Prototype implements Cloneable{ @Override public Prototype clone() throws CloneNotSupportedException{ return (Prototype)super.clone(); } }
2、新建一个具体原型类,继承原型类这个抽象类:
package concreteprototype; import abstractprototype.Prototype; import lombok.Getter; import lombok.Setter; /** * Created by Administrator on 2017/8/4. */ @Getter @Setter public class ConcretePrototype extends Prototype implements Cloneable{ private String name; /** * 性别 */ private String gender; private int age; /** * 引用‘工作经历’对象 */ private WorkExperience workExperience; /** * 在具体原型类实例化的同时,实例化‘工作经历’ * @param name */ public ConcretePrototype(String name) { this.name = name; workExperience = new WorkExperience(); } /** * s设置基本信息 * @param gender * @param age */ public void setBasicInfo(String gender,int age){ this.gender = gender; this.age = age; } /** * 设置工作经历 * @param workTime * @param company */ public void setWorkExp(String workTime,String company){ workExperience.setWorkDate(workTime); workExperience.setCompany(company); } /** * 效果展示 */ public void display(){ System.out.println(name + " " + gender + " " + age); System.out.println(workExperience.getWorkDate() + " " + workExperience.getCompany()); } @Override public Prototype clone() throws CloneNotSupportedException{ return super.clone(); } }
3、新建工作经历类:
package concreteprototype; import abstractprototype.Prototype; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; /** * Created by Administrator on 2017/8/4. */ @NoArgsConstructor @Getter @Setter public class WorkExperience{ private String workDate; private String company; }
4、新建测试类:
import concreteprototype.ConcretePrototype; import org.junit.Test; /** * Created by Administrator on 2017/8/4. */ public class TestPrototype { @Test public void testPrototype() throws CloneNotSupportedException { ConcretePrototype personNumberA = new ConcretePrototype("赛赛"); personNumberA.setWorkExp("1990-1995","ABC"); personNumberA.setBasicInfo( "男",20); //开始复制 ConcretePrototype personNumberB = (ConcretePrototype) personNumberA.clone(); //更改工作经历 personNumberB.setWorkExp("2000-2005","SUN Java"); personNumberB.setBasicInfo( "女",22); personNumberA.display(); System.out.println("------------------------------------------"); personNumberB.display(); } }
执行效果如下所示:
结果分析:浅复制效果明显有瑕疵,因为两次工作经历都变成了最后一次设置的值,不是我们想要的结果,
接下来是深复制的实现:
1、修改 ‘’工作经历’' 这个类,继承原型类这个抽象类,重写clone()方法:
package concreteprototype; import abstractprototype.Prototype; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; /** * Created by Administrator on 2017/8/4. */ @NoArgsConstructor @Getter @Setter public class WorkExperience extends Prototype{ private String workDate; private String company; @Override public Prototype clone() throws CloneNotSupportedException { return super.clone(); } }
2、修改具体原型类:提供一个私有构造器,参数类型为 “工作经历类” ;修改clone()方法,具体做法是调用私有的构造器,让工作经历 clone 完成,然后再给这个具体原型类
的对象的相关属性赋值,最后返回一个深复制的具体原型类对象。修改后的类如下:
package concreteprototype; import abstractprototype.Prototype; import lombok.Getter; import lombok.Setter; /** * Created by Administrator on 2017/8/4. */ @Getter @Setter public class ConcretePrototype extends Prototype implements Cloneable{ private String name; /** * 性别 */ private String gender; private int age; /** * 引用‘工作经历’对象 */ private WorkExperience workExperience; /** * 在具体原型类实例化的同时,实例化‘工作经历’ * @param name */ public ConcretePrototype(String name) { this.name = name; workExperience = new WorkExperience(); } private ConcretePrototype(WorkExperience workExp){ try { this.workExperience = (WorkExperience) workExp.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } /** * s设置基本信息 * @param gender * @param age */ public void setBasicInfo(String gender,int age){ this.gender = gender; this.age = age; } /** * 设置工作经历 * @param workTime * @param company */ public void setWorkExp(String workTime,String company){ workExperience.setWorkDate(workTime); workExperience.setCompany(company); } /** * 效果展示 */ public void display(){ System.out.println(name + " " + gender + " " + age); System.out.println(workExperience.getWorkDate() + " " + workExperience.getCompany()); } /** * 调用私有的构造器,让工作经历 clone 完成,然后再给这个具体原型类的对象的相关属性赋值, * 最后返回一个深复制的具体原型类对象 * @return * @throws CloneNotSupportedException */ @Override public Prototype clone() throws CloneNotSupportedException{ ConcretePrototype concretePrototype = new ConcretePrototype(this.workExperience); concretePrototype.name = this.name; concretePrototype.gender = this.gender; concretePrototype.age = this.age; return concretePrototype; } }
3、测试类保持不变。
执行结果如下所示:
嗯,总结在前面以及文中引用的那篇文章总结的很清晰了,到此原型模式基本介绍结束了。