第十四篇:原型模式

原型模式就是用来生成同样的对象的!比如你的简历,你创建好一份简历之后,通过打印机不断的打印就能创建出多份相同的简历出来,这些简历内容都是一模一样的,用程序来表示的话,就是虽然对象不同(内存地址不同),但属性都是一模一样...

我们看看如果不用原型模式的话会是什么样子:

//一份简历
class Resume{
	private String name ;//你的姓名
	private String phone;//你的联系电话
	private String email;//你的邮箱
	private List<Work> works = new ArrayList<Work>() ;//你的多份工作经历
	
	public String getName() {return name;}
	public void setName(String name) {this.name = name;}
	public String getPhone() {return phone;}
	public void setPhone(String phone) {this.phone = phone;}
	public String getEmail() {return email;}
	public void setEmail(String email) {this.email = email;}
	public List<Work> getWorks() {return works;}
	public void setWorks(List<Work> works) {this.works = works;}
	//为什么要这样打印一下,要打印内存地址,我们接下来就知道了
	public void show(){
		String res = "当前对象地址:"+this+",引用属性works地址:"+works+"\r\n"
		+"name:"+name+","
		+"phone:"+phone+","
		+"email:"+email+","
		+"works:[\r\n";
		for (Work work : works) {
			res+=("companyName:"+work.getCompanyName()+",content:"+work.getContent()+"\r\n]");
		}
		System.out.println(res);
	}
	
}
//工作经历
class Work{
	private String companyName;//公司名称
	private String content;//工作内容
	
	public Work(String companyName, String content) {
		this.companyName = companyName;
		this.content = content;
	}
	public String getCompanyName() {return companyName;}
	public void setCompanyName(String companyName) {this.companyName = companyName;}
	public String getContent() {return content;}
	public void setContent(String content) {this.content = content;}
	
}


public class Test {
	public static void main(String[] args) {
		//创建一份简历
		Resume rOne = new Resume();
		rOne.setName("段誉");
		rOne.setPhone("18359612332");
		rOne.setEmail("98785545@qq.com");
		rOne.getWorks().add(new Work("阿里巴巴科技公司", "智能助手系统架构..."));
		//创建二份简历
		Resume rTwo = new Resume();
		rTwo.setName("段誉");
		rTwo.setPhone("18359612332");
		rTwo.setEmail("98785545@qq.com");
		rTwo.getWorks().add(new Work("阿里巴巴科技公司", "智能助手系统架构..."));
		//创建三份简历
		Resume rThree = new Resume();
		rThree.setName("段誉");
		rThree.setPhone("18359612332");
		rThree.setEmail("98785545@qq.com");
		rThree.getWorks().add(new Work("阿里巴巴科技公司", "智能助手系统架构..."));
		
		//还有N份...
		
		//你该不会想直接写Resume rTwo = rOne;这种代码吧...拜托,这只是引用...
		//好了,现在你的简历你要加上学历...专业...等等内容,怎么办?
		//得每份简历都挨个去加上阿!后面无论是什么修改,你都要修改N次阿!如此,我们的原型模式就可以派上用场咯!
	}
}

输出:***************************************************************

当前对象地址:Resume@961dff,引用属性works地址:[Work@18b81e3]
name:段誉,phone:18359612332,email:98785545@qq.com,works:[
companyName:阿里巴巴科技公司,content:智能助手系统架构...
]
当前对象地址:Resume@1fc6e42,引用属性works地址:[Work@1aaf0b3]
name:段誉,phone:18359612332,email:98785545@qq.com,works:[
companyName:阿里巴巴科技公司,content:智能助手系统架构...
]
当前对象地址:Resume@1a082e2,引用属性works地址:[Work@f0c85e]
name:段誉,phone:18359612332,email:98785545@qq.com,works:[
companyName:阿里巴巴科技公司,content:智能助手系统架构...
]

**********************************************************************


现在我们对代码稍微改动一下用原型模式来对对象进行复制吧!

//一份简历,实现克隆接口
class Resume implements Cloneable{
	private String name ;//你的姓名
	private String phone;//你的联系电话
	private String email;//你的邮箱
	private List<Work> works = new ArrayList<Work>() ;//你的多份工作经历
	
	public String getName() {return name;}
	public void setName(String name) {this.name = name;}
	public String getPhone() {return phone;}
	public void setPhone(String phone) {this.phone = phone;}
	public String getEmail() {return email;}
	public void setEmail(String email) {this.email = email;}
	public List<Work> getWorks() {return works;}
	public void setWorks(List<Work> works) {this.works = works;}
	
	//覆盖次克隆方法
	@Override
	public Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
	
	public void show(){
		String res = "当前对象地址:"+this+",引用属性works地址:"+works+"\r\n"
		+"name:"+name+","
		+"phone:"+phone+","
		+"email:"+email+","
		+"works:[\r\n";
		for (Work work : works) {
			res+=("companyName:"+work.getCompanyName()+",content:"+work.getContent()+"\r\n]");
		}
		System.out.println(res);
	}
	
}
public class Test {
	public static void main(String[] args) throws CloneNotSupportedException {
		//创建一份简历
		Resume rOne = new Resume();
		rOne.setName("段誉");
		rOne.setPhone("18359612332");
		rOne.setEmail("98785545@qq.com");
		rOne.getWorks().add(new Work("阿里巴巴科技公司", "智能助手系统架构..."));
		//使用克隆创建第二份简历
		Resume rTwo = (Resume) rOne.clone();
		//使用克隆创建第三份简历
		Resume rThree = (Resume) rOne.clone();
		rOne.show();
		rTwo.show();
		rThree.show();
	}
}


我们看到,简历类实现了我们的Cloneable接口并且覆盖了clone()方法,现在我们的Test类不再需要多次创建对象了,只需要调用原生对象的clone()方法,就可以完整的克隆出一个新的对象!
然而,我们来看一下Test类的输出,你会发现存在一个问题:
输出**********************************************************

当前对象地址:Resume@fcfa52,引用属性works地址:[Work@961dff]
name:段誉,phone:18359612332,email:98785545@qq.com,works:[
companyName:阿里巴巴科技公司,content:智能助手系统架构...
]
当前对象地址:Resume@18b81e3,引用属性works地址:[Work@961dff]
name:段誉,phone:18359612332,email:98785545@qq.com,works:[
companyName:阿里巴巴科技公司,content:智能助手系统架构...
]
当前对象地址:Resume@1fc6e42,引用属性works地址:[Work@961dff]
name:段誉,phone:18359612332,email:98785545@qq.com,works:[
companyName:阿里巴巴科技公司,content:智能助手系统架构...
]

**********************************************************

我们可以看到,虽然Resume是一个崭新的对象(内存地址不同),但它的属性并不是完全崭新的,仔细看它的works属性,这是一个引用属性,我们可以看到,它的内存地址还是一样的!这就存在问题了,在某些情况下,可能需要对引用属性进行操作,此时无论是操作rOne还是rTwo的works,实际上都是在操作同一个对象!那么这种还存在有同样引用的克隆方式,我们称之为浅克隆,与之相反的是深克隆,既任何属性都是崭新的

要实现深克隆,需要我们改写clone方法,比如这样:

//一份简历,实现克隆接口
class Resume implements Cloneable{
	
	//省略...
	
	//覆盖次克隆方法
	@Override
	public Object clone() throws CloneNotSupportedException {
		Resume resume =  (Resume) super.clone();
		
		//让works也构建一份新的
		List<Work> newWorks = new ArrayList<Work>();
		newWorks.addAll(this.works);
		resume.works = newWorks;
		return resume;
	}
	
	//省略
	
}

好了,原型模式就这些,它的实现主要依赖于JDK的Cloneable接口,需要注意的是它的浅克隆和深克隆!很简单吧!





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值