原型模式
什么是原型模式?
用原型实例指定创建创建对象的种类,并且拷贝这些原型创建新的对象
原型模式解决了什么问题?
原型模式是根据已有的类创建一个相同状态的类,不需要再重新初始话一个类,动态获取了对象运行的状态。
如何使用原型模式?
Object类中默认定义了一个clone方法权限为Protected,我们需要重写这个方法并且增大权限为public。
java类库中定义了一个Cloneable接口,我们实现这个接口,尽管这个接口是空的。继承了这个接口,jvm才认为这个类是可以被克隆的。
由于原型模式比较简单,直接举例实现吧
浅克隆
创建一个具体的原型类,实现Cloneable接口,并且重写Object的clone方法,为了便于观察,我也重写了toString
public class ConcretePrototype implements Cloneable {
private String name;
private String age;
public ConcretePrototype() {
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public ConcretePrototype(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected ConcretePrototype clone() {
try {
ConcretePrototype clone = (ConcretePrototype )super.clone();
return clone;
} catch (CloneNotSupportedException e) {
System.out.println("不支持克隆");
}
return null;
}
@Override
public String toString() {
return "ConcretePrototype{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
}
客户端类使用
public class Client {
public static void main(String[] args) {
ConcretePrototype c1 = new ConcretePrototype("小王");
c1.setAge("20");
ConcretePrototype c2 = c1.clone();
c2.setAge("22");
System.out.println(c1);
System.out.println(c2);
}
}
//输出
//ConcretePrototype{name='小王', age='20'}
//ConcretePrototype{name='小王', age='22'}
为什么说是浅克隆呢?
因为这种处理方法只能复制值,而对于引用型数据,则不会复制,此时克隆引用型数据,其所有相应变量相当于指针,指向同一个地址。
String类虽然是引用型,但也具有“值”的特性。
用一个例子复现
使用一个工作经验类当引用型数据
public class WorkExperience {
private String experience;
public WorkExperience() {
}
public WorkExperience(String experience) {
this.experience = experience;
}
public String getExperience() {
return experience;
}
public void setExperience(String experience) {
this.experience = experience;
}
@Override
public String toString() {
return "WorkExperience{" +
"experience='" + experience + '\'' +
'}';
}
}
public class Resume implements Cloneable{
private WorkExperience work;
private String name;
public Resume(String name) {
this.work = new WorkExperience();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setWork(String years){
work.setExperience(years);
}
@Override
protected Resume clone() {
try {
return (Resume)super.clone();
}catch (Exception e){
System.out.println("不支持克隆");
}
return null;
}
@Override
public String toString() {
return "Resume{" +
"work=" + work +
", name='" + name + '\'' +
'}';
}
}
public class Client {
public static void main(String[] args) {
Resume r1 = new Resume("小王");
r1.setWork("三年开发");
Resume r2 = r1.clone();
r2.setWork("半年开发");
System.out.println(r1);
System.out.println(r2);
}
}
//输出
//Resume{work=WorkExperience{experience='半年开发'}, name='小王'}
//Resume{work=WorkExperience{experience='半年开发'}, name='小王'}
深克隆
深克隆即可解决引用类数据可复制使用的问题
以上面的浅克隆为例,我们把浅克隆改成深克隆
public class WorkExperience implements Cloneable{
private String experience;
public WorkExperience() {
}
public WorkExperience(String experience) {
this.experience = experience;
}
public String getExperience() {
return experience;
}
public void setExperience(String experience) {
this.experience = experience;
}
@Override
public String toString() {
return "WorkExperience{" +
"experience='" + experience + '\'' +
'}';
}
@Override
protected WorkExperience clone() {
try{
return (WorkExperience)super.clone();
}catch (Exception e){
System.out.println("不支持克隆");
}
return null;
}
}
public class Resume implements Cloneable{
private WorkExperience work;
private String name;
public Resume(String name) {
this.work = new WorkExperience();
this.name = name;
}
public WorkExperience getWork() {
return work;
}
public void setWorks(WorkExperience work) {
this.work = work;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setWork(String years){
work.setExperience(years);
}
@Override
protected Resume clone() {
try {
Resume resume = (Resume) super.clone();
WorkExperience workExperience = work.clone();
resume.setWorks(workExperience);
return resume;
}catch (Exception e){
System.out.println("不支持克隆");
}
return null;
}
@Override
public String toString() {
return "Resume{" +
"work=" + work +
", name='" + name + '\'' +
'}';
}
}
客户端类仍然相同,但结果为
Resume{work=WorkExperience{experience='三年开发'}, name='小王'}
Resume{work=WorkExperience{experience='半年开发'}, name='小王'}