原型模式详解
2020-06-16 本文已影响0人
奋斗的韭菜汪
不通过new(构造方法)创建对象,通过clone,或者copy的操作创建对象
使用场景:
1、类初始化消耗资源较多
2、new产生的一个对象需要非常繁琐的过程(数据准备、访问权限等)
3、构造函数比较复杂
4、循环体中产生大量的对象时(比较常见)
浅克隆
jdk 的Cloneable是一个浅克隆
修改克隆对象后,原型对象也会发生变化(对于string这种应用类型clone只是copy了指针,并没有copy具体的值,修改是修改具体的值,所有原对象也会发生改变)
深克隆
1、序列化和反序列化
2、对象转json字符串,json字符串再转对象
深克隆的问题:性能不好,占用io
可以破坏单例(解决办法:不实现Cloneable接口,或者实现Cloneable接口重写clone方法,返回单例模式对外提供的唯一一个实例)
原型模式和单例模式是冲突的,不能同时存在一个对象中
1、简单实现:
public class BeanUtils {
public static Object copy(Object prototype){
Class clazz = prototype.getClass();
Object instance = null;
try {
instance = clazz.newInstance();
for(Field field : clazz.getDeclaredFields()){
field.setAccessible(true);
field.set(instance, field.get(prototype));
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return instance;
}
}
public class ExamPaper {
private String attribute1;
private String attribute2;
private String attribute3;
private String attribute4;
private String attribute5;
private String attribute6;
private String attribute11;
private String attribute7;
private String attribute8;
private String attribute9;
private String attribute10;
public ExamPaper copy(){
ExamPaper examPaper = new ExamPaper();
examPaper.setAttribute1(this.attribute1);
examPaper.setAttribute2(this.attribute2);
examPaper.setAttribute3(this.attribute3);
examPaper.setAttribute4(this.attribute4);
examPaper.setAttribute5(this.attribute5);
examPaper.setAttribute6(this.attribute6);
examPaper.setAttribute7(this.attribute7);
examPaper.setAttribute8(this.attribute8);
examPaper.setAttribute9(this.attribute9);
examPaper.setAttribute10(this.attribute10);
examPaper.setAttribute11(this.attribute11);
return examPaper;
}
public String getAttribute1() {
return attribute1;
}
public void setAttribute1(String attribute1) {
this.attribute1 = attribute1;
}
public String getAttribute2() {
return attribute2;
}
public void setAttribute2(String attribute2) {
this.attribute2 = attribute2;
}
public String getAttribute3() {
return attribute3;
}
public void setAttribute3(String attribute3) {
this.attribute3 = attribute3;
}
public String getAttribute4() {
return attribute4;
}
public void setAttribute4(String attribute4) {
this.attribute4 = attribute4;
}
public String getAttribute5() {
return attribute5;
}
public void setAttribute5(String attribute5) {
this.attribute5 = attribute5;
}
public String getAttribute6() {
return attribute6;
}
public void setAttribute6(String attribute6) {
this.attribute6 = attribute6;
}
public String getAttribute11() {
return attribute11;
}
public void setAttribute11(String attribute11) {
this.attribute11 = attribute11;
}
public String getAttribute7() {
return attribute7;
}
public void setAttribute7(String attribute7) {
this.attribute7 = attribute7;
}
public String getAttribute8() {
return attribute8;
}
public void setAttribute8(String attribute8) {
this.attribute8 = attribute8;
}
public String getAttribute9() {
return attribute9;
}
public void setAttribute9(String attribute9) {
this.attribute9 = attribute9;
}
public String getAttribute10() {
return attribute10;
}
public void setAttribute10(String attribute10) {
this.attribute10 = attribute10;
}
@Override
public String toString() {
return "ExamPaper{" +
"attribute1='" + attribute1 + '\'' +
", attribute2='" + attribute2 + '\'' +
", attribute3='" + attribute3 + '\'' +
", attribute4='" + attribute4 + '\'' +
", attribute5='" + attribute5 + '\'' +
", attribute6='" + attribute6 + '\'' +
", attribute11='" + attribute11 + '\'' +
", attribute7='" + attribute7 + '\'' +
", attribute8='" + attribute8 + '\'' +
", attribute9='" + attribute9 + '\'' +
", attribute10='" + attribute10 + '\'' +
'}';
}
}
public class Client {
public static void main(String[] args) {
ExamPaper examPaper = new ExamPaper();
examPaper.setAttribute1("1");
examPaper.setAttribute4("4");
examPaper.setAttribute2("2");
examPaper.setAttribute5("50");
System.out.println("源对象:"+examPaper.toString());
ExamPaper copy = (ExamPaper)BeanUtils.copy(examPaper);
System.out.println("copy对象:"+copy);
}
}
2、通用实现:
抽象原型实现
public interface IPrototype<T> {
T clone();
}
具体原型实现
public class ConcretePrototype implements IPrototype {
private int age;
private String name;
private List<String> hobbies;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getHobbies() {
return hobbies;
}
public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}
@Override
public String toString() {
return "ConcretePrototype{" +
"age=" + age +
", name='" + name + '\'' +
", hobbies=" + hobbies +
'}';
}
//这里可以使用set赋值,也可以模仿简单实现内通过反射来赋值
@Override
public ConcretePrototype clone() {
ConcretePrototype concretePrototype = new ConcretePrototype();
concretePrototype.setAge(age);
concretePrototype.setName(name);
return concretePrototype;
}
}
public class Client {
public static void main(String[] args) {
ConcretePrototype concretePrototype = new ConcretePrototype();
concretePrototype.setName("wangzx");
concretePrototype.setAge(10);
List<String> h = new ArrayList<>();
h.add("打球");
h.add("看电影");
concretePrototype.setHobbies(h);
System.out.println("源对象" + concretePrototype.toString());
ConcretePrototype clone = concretePrototype.clone();
clone.setName("lisi");
h.add("上网");
clone.setHobbies(h);
System.out.println("克隆后的对象:" + clone.toString());
//源对象名没有改变???
System.out.println("克隆对象改名后源对象名:" + concretePrototype.toString());
//源对象爱好改变
System.out.println("克隆对象新增爱好后源对象爱好:" + concretePrototype.toString());
}
}
优点:java自带的原型模式是基于内存二进制流的拷贝,比直接new一个对象性能上提升了许多。
可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份并将其状态保存起来,简化了创建过程
缺点:必须配备克隆或者可拷贝的方法,当对已有类进行改造的时候,需要修改代码,违背了开闭原则,深拷贝、浅拷贝需要运用得当