原型(Prototype)模式

原型(Prototype)模式

问题的引入———简历类
定义一个简历类,必须要有姓名,可以设置性别和年龄,可以设置工作经历,最终需要三份简历。

public class Main {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Resume a=new Resume("大鸟");
		a.setPersonalInfo("男", "29");
		a.setWorkExperience("1998-2000", "XX公司");
		Resume b=new Resume("大鸟");
		b.setPersonalInfo("男", "29");
		b.setWorkExperience("1998-2000", "XX公司");
		Resume c=new Resume("大鸟");
		c.setPersonalInfo("男", "29");
		c.setWorkExperience("1998-2000", "XX公司");
		a.display();
		b.display();
		c.display();
	}

}
class Resume{
	private String name;
	private String sex;
	private String age;
	private String timeArea;
	private String company;
	public Resume(String name) {
		this.name=name;
	}
	public void setPersonalInfo(String sex,String age) {
		this.sex=sex;
		this.age=age;
	}
	public void setWorkExperience(String timeArea,String company) {
		this.timeArea=timeArea;
		this.company =company;
	}
	public void display() {
		System.out.println(name+"  "+sex+"  "+age);
		System.out.println("工作经历:"+timeArea+"  "+company);
	}
}

分析:3份简历需要3次实例化,这样很麻烦,一旦出现错误就需要修改很多次。
原型模式的用意是:通过给出一个原型对象来指明所要创建的对象类型,然后用复制这个原型对象的办法创建出更多的同类型对象。
Java对原型模式的支持:
Java语言中已经提供了clone方法,定义在Object类中,需要实现克隆功能的类,只需要实现java.lang.Cloneable接口即可。

public class Main {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Resume a=new Resume("大鸟");
		a.setPersonalInfo("男", "29");
		a.setWorkExperience("1998-2000", "XX公司");
		Resume b=a.clone();
		b.setWorkExperience("1998-2006", "YY公司");
		Resume c=a.clone();
		c.setPersonalInfo("男", "24");
		a.display();
		b.display();
		c.display();
	}

}
class Resume implements Cloneable{
	private String name;
	private String sex;
	private String age;
	private String timeArea;
	private String company;
	public Resume(String name) {
		this.name=name;
	}
	public void setPersonalInfo(String sex,String age) {
		this.sex=sex;
		this.age=age;
	}
	public void setWorkExperience(String timeArea,String company) {
		this.timeArea=timeArea;
		this.company =company;
	}
	public void display() {
		System.out.println(name+"  "+sex+"  "+age);
		System.out.println("工作经历:"+timeArea+"  "+company);
	}
	public Resume clone() {
		try {return (Resume)super.clone(); }
		catch(CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return null;
		
	}
}

优点

  • 客户端的代码简洁多了,而且想改某份简历,只需要对这份简历做一定的修改就可以了,不会影响到其他简历,相同的部分就不用再重复了。
  • 对性能有大的提高,原因在于:每new一次,都需耍执行一次构造函数,如杲构造函数的执行时间很长,那么多次的执行这个初始化操作就太低效。一般在初始化的信息不发生变化的情况下,克隆是最好的办法,这既隐藏了对象创建的细节,又对性能是大大的提高,它等于是不用重新初始化对象,而是动态地获得对象运行时的状态。

浅复制与深复制
上例中‘简历’对象里的数据类型String是值类型(值类型就是基本类型),克隆成功了。clone(方法是这样的:

  • 如果是字段是值类型的,则对该字段执行逐位复制,
  • 如果字段是引用类型,则复制引用但不复制引用的对象;因此原始对象及其副本引用同一对象。就是说如果‘简历’ 类当中本对象引用,那么引用的对象数据不会被克隆。
public class Main {

	public static void main(String[] args) throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		Resume a=new Resume("大鸟");
		a.setPersonalInfo("男", "29");
		a.setWorkExperience("1998-2000", "XX公司");
		Resume b=a.clone();
		b.setWorkExperience("1998-2006", "YY公司");
		Resume c=a.clone();
		c.setWorkExperience("1998-2003", "ZZ公司");
		a.display();
		b.display();
		c.display();
	}

}
class WorkExperience{
	private String workDate;
	private String company;
	public String getWorkDate() {
		return workDate;
	}
	public void setWorkDate(String workDate) {
		this.workDate = workDate;
	}
	public String getCompany() {
		return company;
	}
	public void setCompany(String company) {
		this.company = company;
	}
	
}
class Resume implements Cloneable{
	private String name;
	private String sex;
	private String age;
	private WorkExperience work=new WorkExperience();
	public Resume(String name) {
		this.name=name;
	}
	public void setPersonalInfo(String sex,String age) {
		this.sex=sex;
		this.age=age;
	}
	public void setWorkExperience(String workDate,String company) {
		work.setWorkDate(workDate);
		work.setCompany(company);
	}
	public void display() {
		System.out.println(name+"  "+sex+"  "+age);
		System.out.println("工作经历:"+work.getWorkDate()+"  "+work.getCompany());
		
	}

	public Resume clone() throws CloneNotSupportedException {

		return (Resume) super.clone();

	}
}

只修改了b和c的工作经历,最后都变成了最后修改的c的工作经历。
出错原因:

  • 由于是浅复制,所以对于值类型,没什么问题,但是对于引用类型,就只是复制了引用,引用的还是原来的对象,所以就会出现给a、b、c三个引用设置“工作经历’,,却同时看到三个引用都是最后的设置是一样的,因为这三个引用都指向了最初的同一个对象。
  • ‘浅复制’:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
  • 这里需要把要复制的对象所引用的对象都复制一遍。比如上例,希望a、b、c三个引用的对象都是不同的,称这种方式为‘深复制’ ,深复制把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。
public class Main {

	public static void main(String[] args) throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		Resume a=new Resume("大鸟");
		a.setPersonalInfo("男", "29");
		a.setWorkExperience("1998-2000", "XX公司");
		Resume b=a.clone();
		b.setWorkExperience("1998-2006", "YY公司");
		Resume c=a.clone();
		c.setWorkExperience("1998-2003", "ZZ公司");
		a.display();
		b.display();
		c.display();
	}

}
class WorkExperience implements Cloneable{
	private String workDate;
	private String company;
	public String getWorkDate() {
		return workDate;
	}
	public void setWorkDate(String workDate) {
		this.workDate = workDate;
	}
	public String getCompany() {
		return company;
	}
	public void setCompany(String company) {
		this.company = company;
	}
	public WorkExperience clone() {
		try {
			return (WorkExperience)super.clone();
		}catch(CloneNotSupportedException e) {
			e.printStackTrace();}
		return null;
	}
	
}
class Resume implements Cloneable{
	private String name;
	private String sex;
	private String age;
	private WorkExperience work=new WorkExperience();
	public Resume(String name) {
		this.name=name;
	}
	public void setPersonalInfo(String sex,String age) {
		this.sex=sex;
		this.age=age;
	}
	public void setWorkExperience(String workDate,String company) {
		work.setWorkDate(workDate);
		work.setCompany(company);
	}
	public void display() {
		System.out.println(name+"  "+sex+"  "+age);
		System.out.println("工作经历:"+work.getWorkDate()+"  "+work.getCompany());
		
	}

	public Resume clone(){
		Resume obj=new Resume(name);
		obj.sex=this.sex;
		obj.age=this.age;
		obj.work=work.clone();
		return obj;

	}
}

修改了b和c的工作经历,显示的工作经历就各不相同。

大鸟  男  29
工作经历:1998-2000  XX公司
大鸟  男  29
工作经历:1998-2006  YY公司
大鸟  男  29
工作经历:1998-2003  ZZ公司

克隆的实现方法有两种:浅复制( shallow copy)与深复制(deepcopy)。
浅复制:只克隆按值传递的数据(比如基本数据类型.String类型)
深复制:除了浅拷贝要克隆的值外,还克隆引用类型(属性的类型也是对象)的数据。
需要注意的是执行深复制后,原来的对象和新创建的对象不会共享任何东西;改变一个对象对另外一个对象没有任何影响。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值