定义
原型模式(Prototype)的实现主要是利用sun公司提供的克隆机制来实现的,在Object这个类中有一个clone方法,这个方法是用protected方法修饰的,所有普通的java类要想具备克隆能力必须去重写这个clone方法,我们可以把这个方法封装到一个抽象类里,想要具备克隆能力就去继承这个抽象类Cloneable。
通过原型模式创建的对象,不仅仅与原型对象具有相同的结构,还与原型对象具有相同的值。
根据对象克隆深度层次的不同,有浅度克隆(共享地址)与深度克隆(不共享地址,重写值)。
优缺点
优点:
- 减少内存消耗,系统资源占用少,所有实例共享同一个方法,不会创建多个。
- 原型对象继承时,子类在重写父类原型方法时很方便,可以调用父类方法,再扩展。
缺点:
如果共享的对象是引用对象(如array)则也会造成多个实例共享同一个array,指向同一个地址,很可能会相互影响。
使用场景
当需要大批量创建新对象而且都是同一个类的对象的时候可以考虑原型模式;
- 通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式;
- 创建对象的时候,我们不只是希望被创建的对象继承其基类的基本结构,还希望继承原型对象的数据;
- 一个对象需要提供给其它对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者。
原型模式实现方法
1.浅克隆
```java / 1..实现一个接口Cloneable 2.重写一个方法clone() / //Video @Data public class Video implements Cloneable { private String name; private Date createTime; }
/ 客户端:克隆 / public class Bilibili { public static void main(String[] args) throws CloneNotSupportedException { //原型对象v1 Date date = new Date(); Video v1 = new Video(“狂神说Java”, date);
//v1克隆v2
//Video v2 = new Video( "狂神说Java", date);
Video v2 = (Video) v1.clone();
System.out.println("v1=>" + v1);
System.out.println("v2=>" + v2);
date.setTime(22131231);
System.out.println("++++++++++++++++++++++++++++++++++++++");
System.out.println("v1=>" + v1);
System.out.println("v2=>" + v2);
}
}
//输出结果 v1=>Video{name=’狂神说Java’, createTime=Thu Dec 10 23:52:48 CST 2020} v2=>Video{name=’狂神说Java’, createTime=Thu Dec 10 23:52:48 CST 2020} ++++++++++++++++++++++++++++++++++++++ v1=>Video{name=’狂神说Java’, createTime=Thu Jan 01 14:08:51 CST 1970} v2=>Video{name=’狂神说Java’, createTime=Thu Jan 01 14:08:51 CST 1970}
发现浅克隆的克隆对象与原型对象指向同一个地址,会相互影响!
<a name="jDctg"></a>
### 2.深克隆
```java
//Video
@Data
public class Video implements Cloneable { //无良up 主,克隆别人的视频! .
private String name;
private Date createTime;
@Override
protected Object clone() throws CloneNotSupportedException {
Object v1 = super.clone();
//实现深克隆~序列化, 反序列化
Video v2 = (Video) v1;
v2.createTime = (Date) this.createTime.clone();//将这个对象的属性也进行克隆~ this就是v1
return v2;
}
}
----------------------------------------------------------------------------------------------
/*
客户端:克隆
*/
public class Bilibili {
public static void main(String[] alrgs) throws CloneNotSupportedException {
//原型对象v1
Date date = new Date();
Video v1 = new Video("狂神说Java", date);
//v1克隆v2
//Video v2 = new Video( "狂神说Java", date);
Video v2 = (Video) v1.clone();
System.out.println("v1=>" + v1);
System.out.println("v2=>" + v2);
date.setTime(22131231);
System.out.println("+++++++++++++++++++++++++++++++++++");
System.out.println("v1=>" + v1);
System.out.println("v2=>" + v2);
}
}
-------------------------------------------------------------------------------------------------
//*输出结果*
v1=>Video{name='狂神说Java', createTime=Thu Dec 10 23:56:38 CST 2020}
v2=>Video{name='狂神说Java', createTime=Thu Dec 10 23:56:38 CST 2020}
+++++++++++++++++++++++++++++++++++
v1=>Video{name='狂神说Java', createTime=Thu Jan 01 14:08:51 CST 1970}
v2=>Video{name='狂神说Java', createTime=Thu Dec 10 23:56:38 CST 2020}
发现深克隆的克隆对象与原型对象被重写的部分属性CreateTime不共享同一个地址了,数据改变不会相互影响!
JDK中的原型模式
拷贝是比new更快的创建对象方法,当需要大批量创建新对象而且都是同一个类的对象的时候可以考虑原型模式。但要注意一般的克隆只是浅克隆(浅克隆:只是对象的hash值不一样,但是对象里面的对象成员变量的hash值是一样的)有些场景可能需要深克隆,这时我们就需要重写clone方法,以ArrayList为例