快速导航
一、代码示例(浅克隆、深克隆)
二、克隆方式破坏单例模式
三、jdk中使用原型模式
原型模式介绍
定义:原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
不需要知道任何创建的细节,不调用构造函数。
类型:创建型
适用场景:
类初始化消耗较多资源
new 产生的一个对象需要非常繁琐的过程(数据准备、访问权限)
构造函数比较复杂
循环体中生产大量对象时
优点:
简化创建过程
性能比new 一个对象性能高
缺点:
必须配备克隆方法
对克隆复杂对象或对克隆出的对象进行复杂改造时,容易引入风险
深拷贝、浅拷贝要运用得当(深克隆还需要对某些属性做修改)
一、代码示例(浅克隆、深克隆)
/**
* @program: adpn-pattern->Computer
* @description: 电脑实例
* @author: Jstar
* @create: 2019-11-24 11:58
**/
public class Computer implements Cloneable{
private String name;
private String software;
private Date createTime;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public Computer(String name, String software, Date createTime) {
this.name = name;
this.software = software;
this.createTime = createTime;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSoftware() {
return software;
}
public void setSoftware(String software) {
this.software = software;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
@Override
public String toString() {
return "Computer{" +
"name='" + name + '\'' +
", software='" + software + '\'' +
", createTime=" + createTime +
'}';
}
}
//测试类
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
Date date = new Date(0L);
Computer computer1 = new Computer("联想", "win7", date);
Computer computer2 = (Computer) computer1.clone();
System.out.println(computer1);
System.out.println(computer2);
System.out.println(computer1==computer2);
}
}
看一下运行结果:
虽然toString 值相同,但是这两个却不是一个对象。
// 测试改变 computer1 的 createTime
结果是 computer2 的 createTime 也改变了。
Debug 查看一下:
虽然computer1 和 computer2对象不同,但 引用型对象 createTime 却指向同一个地址,这就是导致他们 createTime 相同的原因。 这种就是浅拷贝。
如何能做到 createTime 也不同呢,也就是深拷贝解决的问题。我们来改一下 Computer 的 clone() 方法。
@Override
protected Object clone() throws CloneNotSupportedException {
Computer computer = (Computer) super.clone();
computer.createTime= (Date) computer.getCreateTime().clone();
return computer;
}
测试一下:
引用类型变量也不再是同一个地址,这样就实现了深克隆。
二、克隆方式破坏单例模式
代码:
/**
* @program: adpn-pattern->HungrySinglon
* @description: 饿汉式单例模式
* @author: Jstar
* @create: 2019-11-23 11:12
**/
public class HungrySinglon implements Serializable,Cloneable {
private final static HungrySinglon hungrySinglon=new HungrySinglon();
private HungrySinglon(){
if(hungrySinglon!=null){
throw new RuntimeException("不允许使用私有构造器创建对象");
}
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static HungrySinglon getInstance(){
return hungrySinglon;
}
public Object readResolve(){
return hungrySinglon;
}
}
/**
* @program: adpn-pattern->HungryCloneTest
* @description: 演示克隆破坏单例模式
* @author: Jstar
* @create: 2019-11-24 15:51
**/
public class HungryCloneTest {
public static void main(String[] args) throws CloneNotSupportedException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
HungrySinglon instance = HungrySinglon.getInstance();
Class<HungrySinglon> hungrySinglonClass = HungrySinglon.class;
Method clone = hungrySinglonClass.getDeclaredMethod("clone");
clone.setAccessible(true);
HungrySinglon instance2 = (HungrySinglon) clone.invoke(instance);
System.out.println(instance);
System.out.println(instance2);
}
}
运行结果:
单例模式已被 反射和克隆破坏了。
如果是这种情况,怎么保证单例呢。
解决方法有2个:
1、单例实例不继承 Cloneable,不重写 clone()方法。
2、在克隆方法内返回单例实体。即:
@Override
protected Object clone() throws CloneNotSupportedException {
return hungrySinglon;
}
这样创建的单例对象就是同一个了。