什么是原型模式
在GOF的《设计模式:可复用面向对象软件的基础》中是这样说的:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。在这个定义中,最重要的一个词是“拷贝”,也就是口头上的复制,而这个拷贝,也就是原型模式的精髓所在。
简而言之就是复制一个已有的对象,复制的新对象的属性和已有对象完全一致
原型模式的优缺点
- 创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率
- 不用重新初始化对象,而是动态地获得对象运行时的状态
- 如果原始对象发生变化(增加或者减少属性),其它克隆对象的也会发生相应的变化,无需修改代码
- 在实现深克隆的时候可能需要比较复杂的代码
- 需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有
的类进行改造时,需要修改其源代码,违背了ocp原则,这点请同学们注意.
原型模式的几种分类
1.浅拷贝:简单数据类型的成员属性复制一份,复杂数据类型成员属性引用已有的实例的属性
2.深拷贝(有两种实现方式):所有属性都复制一份
1)重写clone()方法手动拷贝各复杂数据类型成员属性
2)使用序列化实现深拷贝
浅拷贝
代码:
public class Type01 {
public static void main(String[] args){
Student s1=new Student("张三");
Student s2=new Student("李四");
s1.setFriend(s2);
Student s3= (Student) s1.clone();
System.out.println(s1==s2);
System.out.println(s1.getFriend()==s3.getFriend());
}
}
class Student implements Cloneable{
private String name;
public String getName() {
return name;
}
public Student getFriend() {
return friend;
}
private Student friend;
public Student(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public void setFriend(Student friend) {
this.friend = friend;
}
@Override
public Object clone() {
Object o=null;
try {
o=super.clone();
}catch (Exception e){
e.printStackTrace();
}
return o;
}
}
输出:
false
true
注意:
1.必须重写clone()方法,因为父类的clone()方法的修饰符是protected的
2.建议将重写的clone()方法修饰符改为public,避免其他包的类无法访问
3.不实现Cloneable接口会报CloneNotSupportedException异常
4.被拷贝的对象的复杂类型属性不会创建新的,而是引用已有的
深拷贝一 (手动拷贝)
代码:
public class Type02 {
public static void main(String[] args){
Student s1=new Student("张三");
Student s2=new Student("李四");
s1.setFriend(s2);
Student s3= (Student) s1.clone();
System.out.println(s1==s2);
System.out.println(s1.getFriend()==s3.getFriend());
}
}
class Student implements Cloneable{
private String name;
public String getName() {
return name;
}
public Student getFriend() {
return friend;
}
private Student friend;
public Student(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public void setFriend(Student friend) {
this.friend = friend;
}
@Override
public Object clone() {
Student o=null;
try {
o=(Student)super.clone();
}catch (Exception e){
e.printStackTrace();
}
Student f=null;
//例子举得不太好,递归了,this.friend.friend是null,所以加个判断,避免空指针异常
if (this.friend != null) {
f=(Student)this.friend.clone();
}
o.setFriend(f);
return o;
}
}
输出:
false
false
注意: 显然这很麻烦,无限套娃,实用性较低
深拷贝二(使用序列化)
代码:
import java.io.*;
public class Type03 {
public static void main(String[] args){
Student s1=new Student("张三");
Student s2=new Student("李四");
s1.setFriend(s2);
Student s3= (Student) s1.clone();
System.out.println(s1.getName());
System.out.println(s3.getName());
System.out.println(s1.getFriend().getName());
System.out.println(s3.getFriend().getName());
System.out.println(s1==s2);
System.out.println(s1.getFriend()==s3.getFriend());
}
}
class Student implements Cloneable, Serializable {
private String name;
public String getName() {
return name;
}
public Student getFriend() {
return friend;
}
private Student friend;
public Student(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public void setFriend(Student friend) {
this.friend = friend;
}
@Override
public Object clone() {
Object o=null;
ObjectOutputStream oos;
ObjectInputStream ois;
ByteArrayOutputStream bos;
ByteArrayInputStream bis;
try {
bos=new ByteArrayOutputStream();
oos=new ObjectOutputStream(bos);
oos.writeObject(this);
bis=new ByteArrayInputStream(bos.toByteArray());
ois=new ObjectInputStream(bis);
o = ois.readObject();
}catch (Exception e){
e.printStackTrace();
}finally {
if (ois == null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bis == null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (oos == null) {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bos == null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return o;
}
}
输出:
张三
张三
李四
李四
false
false
推荐使用这种方式
转载:https://blog.csdn.net/m0_47553984/article/details/106177132
查看评论