该项目源码地址:https://github.com/lastwhispers/code/tree/master/java-basic/design-pattern
(设计模式相关代码与笔记)
1. 定义
指原型实例指定创建对象的种类,并通过克隆这些原型创建新的对象
2. 适用场景
- 类初始化消耗较多资源
- new产生的一个对象需要非常繁琐的过程(数据准备、访问权限等)
- 构造函数比较复杂
- 循环体中生产大量对象时
3. 深浅克隆
浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
总之深浅克隆都会在堆中新分配一块区域,区别在于对象属性引用的对象是否需要进行克隆(递归性的)。
4. 模式实例
原型模式就是让类实现Cloneable接口,达到克隆原型类的方式。
4.1 深浅克隆原型对比
复印简历各位都应该做过吧!这里我们利用原型模式来模拟复印简历。
(1)简历类
import java.util.Date;
public class Resume implements Cloneable {
private String name;
private Date birthday;
private String sex;
private String school;
private String timeArea;
private String company;
public Resume(String name, Date birthday, String sex, String school, String timeArea, String company) {
this.name = name;
this.birthday = birthday;
this.sex = sex;
this.school = school;
this.timeArea = timeArea;
this.company = company;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
public String getTimeArea() {
return timeArea;
}
public void setTimeArea(String timeArea) {
this.timeArea = timeArea;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
/**
* 克隆该实例
*/
@Override
public Object clone() {
Resume resume = null;
try {
resume = (Resume) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return resume;
}
public void display() {
System.out.println("姓名:" + name);
System.out.println("生日:" + birthday + ",性别:" + sex + ",毕业学校:" + school);
System.out.println("工作年限:" + timeArea + ",公司:" + company);
}
}
(2)测试类
public class Test {
public static void main(String[] args) {
//原型A对象
Resume a = new Resume("小李子",new Date(), "男", "XX大学","2012.09.05", "XX科技有限公司");
a.display();
System.out.println("*************克隆简历**************");
//克隆B对象
Resume b = (Resume) a.clone();
b.display();
System.out.println("***************比较***************");
/*
* 测试A==B?
* 对任何的对象x,都有x.clone() !=x,即克隆对象与原对象不是同一个对象
*/
System.out.print("比较:A==B?");
System.out.println( a == b);
b.getBirthday().setTime(666666666666L);
System.out.println("修改B简历的Birthday为:"+b.getBirthday());
System.out.println("查看A简历的Birthday为:"+a.getBirthday());
/*
* 比较Date对象
*/
System.out.print("比较:A.Date==B.Date?");
System.out.println(a.getBirthday() == b.getBirthday());
}
}
(3)测试结果
可以发现B在克隆A的birthday时,是直接克隆的引用。这种是浅克隆。
浅克隆(4)修改为深克隆
@Override
public Object clone() {
Resume resume = null;
try {
resume = (Resume) super.clone();
resume.birthday = (Date) resume.birthday.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return resume;
}
再次测试,可以发现B在克隆A的birthday时,是重新克隆的birthday,而不是直接克隆的引用。
深克隆4.2 抽象原型类
public abstract class A implements Cloneable{
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class B extends A{
public static void main(String[] args) throws CloneNotSupportedException {
B b = new B();
b.clone();
}
}
5. 优缺点
优点:
- 当创建对象的实例较为复杂的时候,使用原型模式可以简化对象的创建过程,通过复制一个已有的实例可以提高实例的创建效率。
- 扩展性好。由于原型模式提供了抽象原型类,在客户端针对抽象原型类进行编程,而将具体原型类写到配置文件中,增减或减少产品对原有系统都没有影响。
- 可以使用深克隆方式保存对象的状态。使用原型模式将对象复制一份并将其状态保存起来,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。
缺点:
- 需要为每一个类配置一个克隆方法,而且该克隆方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违反了“开闭原则”。
- 在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。
6. 扩展-JDK1.7源码中的原型模式
ArrayList的clone()
HashMap的clone()
CacheKey的clone()
网友评论