大话设计模式读书笔记(七) 原型模式

原型模式(Prototype):

书中通过小菜要去面试,需要打印简历。而引出了需求。 需要小菜写一份简历类,要求有姓名,年龄,性别。可以设置工作经历,并且需要三份简历。

未使用设计模式代码:

package Prototype.NoPattern;

public class Resume {
	private String name;//姓名
	private int age; //年龄
	private String sex; //性别
	
	private String timeAree; //工作时长
	private String company; //公司
	
	public void setPersonInfo(int age,String sex){//设置个人信息
		this.age = age;
		this.sex = sex;
	}
	
	public void setWorkExperience(String timeAree,String company){//设置工作经历
		this.timeAree = timeAree;
		this.company = company;
	}
	
	public void display(){//显示
		System.out.println(name+"  "+age+"  "+sex);
		System.out.println("工作经历:"+company +";工作年限:"+timeAree);
	}
	public Resume(String name) {
		super();
		this.name = name;
	}
}
主程序代码:
public class Main {
	public static void main(String[] args) {
		Resume a = new Resume("大鸟");
		a.setPersonInfo(25, "男");
		a.setWorkExperience("2008-2010", "xx公司");
		
		Resume b = new Resume("大鸟");
		b.setPersonInfo(25, "男");
		b.setWorkExperience("2008-2010", "xx公司");
		
		Resume c = new Resume("大鸟");
		c.setPersonInfo(25, "男");
		c.setWorkExperience("2008-2010", "xx公司");
		
		a.display();
		b.display();
		c.display();
	}
}

按照大鸟的话来说,这就相当于 在以前没有打印的年代,手写代码一样。 当需要三份简历的时候,就需要些三次,如果需要二十份,则需要实例化二十次。而且当有一个地方出现错误的时候,需要改20处。很显然这样是很不好的。于是引出了设计模式:原型模式。

原型模式(Prototype):

原型模式:用原型实例制定创建类型的种类,并通过克隆这些原型创建新的对象。

原型模式UML类图:



源代码:

public interface Prototype extends Cloneable{//抽象克隆对象
	public Object clone();
}
public class ConcretePrototype implements Prototype{//具体克隆对象	
	public Object clone(){//最简单的克隆方法,由于没有属性就不复制值了
		Prototype prototype = new ConcretePrototype();
		return prototype;
	}
}

public class Client {
	private Prototype prototype;//持有需要使用的原型接口对象

	public Client(Prototype prototype) {//构造方法,需要传入一个需要克隆的对象
		super();
		this.prototype = prototype;
	}
	public Prototype operation(){
		ConcretePrototype concretePrototype =(ConcretePrototype) prototype.clone();
		return concretePrototype ;
	}
}

Java中的克隆:

Java的所有类都是从java.lang.Object类继承而来的,而Object类提供protected Object clone()方法对对象进行复制,子类当然也可以把这个方法置换掉,提供满足自己需要的复制方法。对象的复制有一个基本问题,就是对象通常都有对其他的对象的引用。当使用Object类的clone()方法来复制一个对象时,此对象对其他对象的引用也同时会被复制一份

  Java语言提供的Cloneable接口只起一个作用,就是在运行时期通知Java虚拟机可以安全地在这个类上使用clone()方法。通过调用这个clone()方法可以得到一个对象的复制。由于Object类本身并不实现Cloneable接口,因此如果所考虑的类没有实现Cloneable接口时,调用clone()方法会抛出CloneNotSupportedException异常。

克隆满足的条件:

clone()方法将对象复制了一份并返还给调用者。所谓“复制”的含义与clone()方法是怎么实现的。一般而言,clone()方法满足以下的描述:

1.在派生类中覆盖基类的clone()方法,并声明为public【Object类中的clone()方法为protected的】。 
2.在派生类的clone()方法中,调用super.clone()。 
3.在派生类中实现Cloneable接口。 

克隆后的对象与原对象比较:

  (1)对任何的对象x,都有:x.clone()!=x。换言之,克隆对象与原对象不是同一个对象。

  (2)对任何的对象x,都有:x.clone().getClass() == x.getClass(),换言之,克隆对象与原对象的类型一样。

  (3)如果对象x的equals()方法定义其恰当的话,那么x.clone().equals(x)应当成立的。

  在JAVA语言的API中,凡是提供了clone()方法的类,都满足上面的这些条件。JAVA语言的设计师在设计自己的clone()方法时,也应当遵守着三个

条件。一般来说,上面的三个条件中的前两个是必需的,而第三个是可选的。

利用原型模式实现简历打印:

public class Resume implements Cloneable{
	private String name;
	private int age;
	private String sex;
	
	private String timeAree;
	private String company;
	
	public void setPersonInfo(int age,String sex){
		this.age = age;
		this.sex = sex;
	}
	
	public void setWorkExperience(String timeAree,String company){
		this.timeAree = timeAree;
		this.company = company;
	}
	
	public void display(){
		System.out.println(name+"  "+age+"  "+sex);
		System.out.println("工作经历:"+company +";工作年限:"+timeAree);
	}
	
	public Resume() {
		super();
	}
	
	public Resume(String name) {
		super();
		this.name = name;
	}
	
	public Resume(String name, int age, String sex, String timeAree, String company) {
		this.name = name;
		this.age = age;
		this.sex = sex;
		this.timeAree = timeAree;
		this.company = company;
	}
	
	public Object clone() throws CloneNotSupportedException{
		return super.clone();
	}
}


  
  
public class Client {//打印方法,通过该方法实现克隆简历,相当于打印功能
	Resume resume ;

	public Client(Resume resume) {
		super();
		this.resume = resume;
	}
	
	public Resume getResume() throws CloneNotSupportedException{
		return  (Resume)resume.clone();
	}
}

public class Main {
	public static void main(String[] args) throws CloneNotSupportedException{
		Resume resume = new Resume("小菜");
		resume.setPersonInfo(18, "男");
		resume.setWorkExperience("2016-2017", "XX公司");
		Client c = new Client(resume);
		
		Resume resume2=c.getResume();
		Resume resume3=c.getResume();
		resume.display();
		resume2.display();
		resume3.display();
	}
}

深克隆与潜克隆:

A:浅复制(浅克隆): 浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。 
b:深复制(深克隆):深复制把要复制的对象所引用的对象都复制了一遍。

浅克隆示例:

public class Dept implements Cloneable{//部门
	String id;
	String name;
	public Dept(String id, String name) {
		this.id = id;
		this.name = name;
	}
	
	public Dept clone() throws CloneNotSupportedException{
		return (Dept) super.clone();
	}
}

public class Emp implements Cloneable{
	String name ; 
	String id;
	Dept dept;
	public Emp(String name, String id, Dept dept) {
		super();
		this.name = name;
		this.id = id;
		this.dept = dept;
	}
	public Emp clone() throws CloneNotSupportedException{
		return (Emp) super.clone();
	}
}

public class Main {
	public static void main(String[] args) throws CloneNotSupportedException {
		Dept d = new Dept("1", "技术部");
		Dept d2 = d.clone();
		System.out.println(d == d2);
		
		Emp e = new Emp("小明", "1", d);
		Emp e2 = e.clone();
		
		System.out.println(e==e2);
		System.out.println(e.dept==e2.dept);
	}
}

结果为:
false
false 
true

因为 浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。 所以复制员工时,员工所引用的部门还是原来员工的部门。
如果要深复制,则只需要将员工中的clone方法修改成如下:
public class Emp implements Cloneable{
	String name ; 
	String id;
	Dept dept;
	public Emp(String name, String id, Dept dept) {
		super();
		this.name = name;
		this.id = id;
		this.dept = dept;
	}
	public Emp clone() throws CloneNotSupportedException{
		Emp emp = (Emp) super.clone();
		emp.dept=dept.clone();
		return emp;
	}
}

也就是在复制员工的同时,将员工所在的部门同时复制一遍。这就进行了深复制。

通过序列化实现深克隆:

public class Dept implements Serializable{
	private static final long serialVersionUID = 6798532648769041110L;
	String id;
	String name;
	public Dept(String id, String name) {
		this.id = id;
		this.name = name;
	}
}

public class Emp implements Serializable{
	String name ; 
	String id;
	Dept dept;
	public Emp(String name, String id, Dept dept) {
		super();
		this.name = name;
		this.id = id;
		this.dept = dept;
	}
	public Object deepClone() throws Exception{
		//将该对象序列化成流,因为写在流里的是对象的一个拷贝,
		//而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝 
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(bos);
		oos.writeObject(this);
		//将流序列化成对象
		ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
		ObjectInputStream ois = new ObjectInputStream(bis);
		return ois.readObject();
	}
}

public class Main {
	public static void main(String[] args) throws Exception {
		Dept d = new Dept("1", "技术部");
		
		Emp e = new Emp("小明", "1", d);
		Emp e2 = (Emp) e.deepClone();
		
		System.out.println(e==e2);
		System.out.println(e.dept==e2.dept);
	}
}

此时,输出的结果一样是false,false.


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值