错误案例
原型模式在实际项目中,应用也非常常见,比如:过年时候,我想要给3个同学发送一封祝福的信,但祝福的信中,有细小的差距,我希望不重新写信了,拷贝原来的信息,然后修改一下,但是由于java值传递的特殊性,可能我修改第二封后,第一封也会被修改,比如:
- 这里模拟信封
package design.prototype;
public class Letter {
public String blessing;
public String end;
public String name;
public Letter(String blessing,String end) {
this.blessing = blessing;
this.end = end;
}
public void setName(String name) {
this.name = name;
}
public void send(){
System.out.println("已经向" + this.name + "发送");
};
public void read(){
System.out.println(this.blessing + this.name + this.end);
};
}
- 这里模拟编辑和发送
public static void main(String[] args) {
Letter letter01 = new Letter("新年到,鸿运照,烦恼的事儿往边靠,爱情滋润没烦恼,祝","新春快了");
letter01.setName("张三");
letter01.send();
Letter letter02 = letter01;
letter02.setName("赵四");
letter02.send();
Letter letter03 = letter02;
letter03.setName("王五");
letter03.send();
letter01.read();
letter02.read();
letter03.read();
}
- 结果就很尴尬了,他们3个都接收到的是“王五”的称呼
已经向张三发送
已经向赵四发送
已经向王五发送
新年到,鸿运照,烦恼的事儿往边靠,爱情滋润没烦恼,祝王五新春快了
新年到,鸿运照,烦恼的事儿往边靠,爱情滋润没烦恼,祝王五新春快了
新年到,鸿运照,烦恼的事儿往边靠,爱情滋润没烦恼,祝王五新春快了
原型模型
这里我们就的想办法,让拷贝赋值后的数据被修改了,也不会影响之前的数据,于是,我们修改代码如下:
- 在Letter中增加一个clone()方法
package design.prototype;
public class Letter {
public String blessing;
public String end;
public String name;
public Letter(String blessing,String end) {
this.blessing = blessing;
this.end = end;
}
public void setName(String name) {
this.name = name;
}
public void send(){
System.out.println("已经向" + this.name + "发送");
};
public void read(){
System.out.println(this.blessing + this.name + this.end);
};
//注意 增加的代码在这里
public Letter clone(){
Letter letter = new Letter(this.blessing,this.end);
letter.setName(this.name);
return letter;
}
}
- 然后主程序中,修改为如下:
public static void main(String[] args) {
Letter letter01 = new Letter("新年到,鸿运照,烦恼的事儿往边靠,爱情滋润没烦恼,祝","新春快了");
letter01.setName("张三");
letter01.send();
Letter letter02 = letter01.clone(); //这里改变了
letter02.setName("赵四");
letter02.send();
Letter letter03 = letter02.clone();//这里改变了
letter03.setName("王五");
letter03.send();
letter01.read();
letter02.read();
letter03.read();
}
- 输出就正常了
已经向张三发送
已经向赵四发送
已经向王五发送
新年到,鸿运照,烦恼的事儿往边靠,爱情滋润没烦恼,祝张三新春快了
新年到,鸿运照,烦恼的事儿往边靠,爱情滋润没烦恼,祝赵四新春快了
新年到,鸿运照,烦恼的事儿往边靠,爱情滋润没烦恼,祝王五新春快了
总结
原型模式是不是很简单,相信很多人没有学过原型模式,也会在实际项目中写出原型模式。
- clone():在实际业务中,可能Letter类中还有非基本类型,也就是不能直接赋值,需要再次深度克隆的情况,是否需要深度克隆,需要根据你们的具体业务场景来实现
- Object中也有一个protected类型的clone()方法,我们可以让Letter实现Cloneable接口,然后重写并调用受保护的Object.clone()方法即可
public class Letter implements Cloneable{
… 省略代码 …
@Override
public Object clone() throws CloneNotSupportedException {
// Letter letter = new Letter(this.blessing,this.end);
// letter.setName(this.name);
return super.clone();
}
}
- 调用放入如下
Letter letter02 = (Letter) letter01.clone();
System.out.println(letter02 != letter01); //true 必须的,这样才能保证letter02是另外一个类
System.out.println(letter02.getClass() == letter01.getClass()); // true 相等不是绝对要求
System.out.println(letter02.equals(letter01)); //false 不是绝对要求
这里不深入了,有兴趣的同学可以打开Object类即可看到他详细的讲解