最近买了一本设计模式的书籍看了看,发现自己对设计模式没有什么概念,同时,在看某些设计模式的时候发现在项目中应用了不少,但是是哪个设计模式却说不明白!! 不扯皮,今天记录的是原型模式,java中天然支持原型模式,也就是在jdk层面就支持这个了(clone),代理模式也是(Proxy)。
用原型实例制定创建对象的种类,并通过拷贝这些原型并创建新的对象,相当于是拷贝一份副本
看到这个概念的时候我不禁想起了java的Object类的clone方法么? 难怪java天然支持拷贝模型。话说回来,在java中如果实现克隆对象,要有两个标准
import lombok.Data;
@Data
public class User implements Cloneable{
private String name ;
private int age;
private int sex;
@Override
protected Object clone() {
try {
// 这里是重写clone方法的逻辑
User user = (User) super.clone();
return user;
}catch (CloneNotSupportedException e){
e.printStackTrace();
}
return null;
}
}
再来上一个测试类:
public class Client {
public static void main(String[] args) {
User user = new User();
user.setAge();
User cloneUser = (User)user.clone();
System.out.println(cloneUser);
}
}
####得到结果 ::User(name=null, age=18, sex=0)
结果: 拷贝成功
原理: 因为需要实现cloneable接口,这个接口它是一个标记接口,没有任何方法(跟Serializable一样),jvm用来对标记的对象执行它的clone方法,然后进行内存二进制流的拷贝,因此性能会比new好很多。
这里问题又来了,如果你克隆的对象里面引用了其他对象呢??试试?
@Data
public class User implements Cloneable{
//很多根头发
private ArrayList hairs = new ArrayList();
private String name ;
private int age;
private int sex;
@Override
protected Object clone() {
try {
User user = (User) super.clone();
return user;
}catch (CloneNotSupportedException e){
e.printStackTrace();
}
return null;
}
}
public class Client {
public static void main(String[] args) {
User user = new User();
user.setAge();
user.getHairs().add("aaaa");
User cloneUser = (User)user.clone();
cloneUser.getHairs().add("abc");
System.out.println(cloneUser);
System.out.println(user);
}
}
### User(hairs=[aaaa, abc], name=null, age=18, sex=0)
###User(hairs=[aaaa, abc], name=null, age=18, sex=0)
翻车了? 没错,当对象里面引用另外一个对象的时候,它这里其实是引用这个对象的地址,这种拷贝也就是我们常说的浅拷贝,有人说了,String不就是引用的对象么?注意:String它是jdk提供的不可变对象,它内部是通过final类型的char数组实现的,并没有实现clone 方法,因此它是可以直接被克隆的,与此相同的,比如int Integer,long Long …等等都是可以直接被拷贝的。
那诸如上面的情况,应该如何修改呢?也就是如何修改为深拷贝呢? so essy!!!直接对内部的对象引用也执行clone方法
@Override protected Object clone() { try { User user = (User) super.clone(); user.hairs = (ArrayList) hairs.clone(); return user; }catch (CloneNotSupportedException e){ e.printStackTrace(); } return null; }
对,没错,这里我们在点到ArrayList源码看一下,它是有实现clone方法的
至此,原型模式的栗子就举完毕了 !