Java 设计模式:原型Prototype

原型模式Prototype

  原型模式也是一种对象创建的模式,主要作用是通过拷贝已有对象来生成新对象。它的好处是在实例化对象时不用每一次都使用新建,这样如果在新建对象比较耗时的情况下可以提高程序的运行效率。

 

  原型模式中的拷贝分为浅拷贝和深拷贝

  浅拷贝: 对对象中的值类型进行拷贝,对引用类型不拷贝还是指向相同的引用;

  深拷贝: 对对象中的值类型进行拷贝,对引用类型也拷贝;

 

示例:

  现有简历类,类的属性有姓名、年龄和工作经验,工作经验为引用类型包括公司名称和工作时间

  浅拷贝代码如下:

  工作经验类  WorkExperience

class WorkExperience
{
	private String companyName;
	private int years;
	public WorkExperience (String cname , int years )
	{
		this.companyName = cname ;
		this.years = years;
	}
	public String getCompanyName()
	{
		return companyName;
	}
	public void setCompanyName(String companyName)
	{
		this.companyName = companyName;
	}
	public int getYears()
	{
		return years;
	}
	public void setYears(int years)
	{
		this.years = years;
	}
	
}

  简历类  Resume

class Resume implements Cloneable
{
	private WorkExperience workExperience ;
	
	private String name ;
	
	private int age ;

	public Resume(WorkExperience workExperience, String name, int age)
	{
		super();
		this.workExperience = workExperience;
		this.name = name;
		this.age = age;
	}

	public WorkExperience getWorkExperience()
	{
		return workExperience;
	}

	public void setWorkExperience(WorkExperience workExperience)
	{
		this.workExperience = workExperience;
	}

	public String getName()
	{
		return name;
	}

	public void setName(String name)
	{
		this.name = name;
	}

	public int getAge()
	{
		return age;
	}

	public void setAge(int age)
	{
		this.age = age;
	}
	
	public Object clone()
	{
		try
		{
			return super.clone();  //直接调用父类的clone方法
		}
		catch (CloneNotSupportedException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null ;
		}
	}
	
}

   运行测试1:创建两个工作经验类we1和we2,创建简历类r1 并通过拷贝创建简历类r2.通过set方法修改简历r2的姓名、年龄和工作经验

public class ProtoType
{
	public static void main (String args[])
	{
		WorkExperience we1 = new WorkExperience("公司A", 2);
		WorkExperience we2 = new WorkExperience("公司B", 3);
		
		Resume r1 = new Resume(we1, "小张", 24);
		
		Resume r2= (Resume)r1.clone() ;
		
		r2.setName("小李");
		r2.setAge(30);
		r2.setWorkExperience(we2);
		
		System.out.println(r1.getName()+r1.getAge()+"岁,工作经验"+r1.getWorkExperience().getCompanyName()+","+r1.getWorkExperience().getYears()+"年");
		System.out.println(r2.getName()+r2.getAge()+"岁,工作经验"+r2.getWorkExperience().getCompanyName()+","+r2.getWorkExperience().getYears()+"年");
		
	}
}

    运行结果如下

小张24岁,工作经验公司A,2年
小李30岁,工作经验公司B,3年

  简历类r2 通过set方法修改属性值后未影响r1.

  运行测试2:创建一个工作经验类we,创建简历类r1并通过克隆创建简历类r2 。r2通过set方法修改属性值name、age,并通过getWorkExperience()获取工作经验类后修改工作经验。代码如下

  

public class ProtoType
{
	public static void main (String args[])
	{
		WorkExperience we = new WorkExperience("公司A", 2);
		
		Resume r1 = new Resume(we, "小张", 24);
		
		Resume r2= (Resume)r1.clone() ;
		
		r2.setName("小李");
		r2.setAge(30);
		r2.getWorkExperience().setCompanyName("公司B");
		r2.getWorkExperience().setYears(3);
		
		System.out.println(r1.getName()+r1.getAge()+"岁,工作经验"+r1.getWorkExperience().getCompanyName()+","+r1.getWorkExperience().getYears()+"年");
		System.out.println(r2.getName()+r2.getAge()+"岁,工作经验"+r2.getWorkExperience().getCompanyName()+","+r2.getWorkExperience().getYears()+"年");
		
	}
}

  运行结果

小张24岁,工作经验公司B,3年
小李30岁,工作经验公司B,3年

  简历r2修改工作经验后简历r1中的工作经验也同样被修改了。这是由于浅拷贝中关于引用的拷贝是只拷贝了应用地址,r1和r2中指向了相同的we引用。

 

深拷贝:

  深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。

  工作经验类同样实现 Cloneable 接口

  

class WorkExperience implements Cloneable
{
	private String companyName;
	private int years;
	public WorkExperience (String cname , int years )
	{
		this.companyName = cname ;
		this.years = years;
	}
	public String getCompanyName()
	{
		return companyName;
	}
	public void setCompanyName(String companyName)
	{
		this.companyName = companyName;
	}
	public int getYears()
	{
		return years;
	}
	public void setYears(int years)
	{
		this.years = years;
	}
	
	public Object clone()
	{
		try
		{
			return super.clone();  //直接调用父类的clone方法
		}
		catch (CloneNotSupportedException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null ;
		}
	}
	
}

  

  简历类:简历类中的修改是通过拷贝设置工作经验

  

class Resume implements Cloneable
{
	private WorkExperience workExperience ;
	
	private String name ;
	
	private int age ;

	public Resume(WorkExperience workExperience, String name, int age)
	{
		super();
		this.workExperience = workExperience;
		this.name = name;
		this.age = age;
	}

	public WorkExperience getWorkExperience()
	{
		return workExperience;
	}

	public void setWorkExperience(WorkExperience workExperience)
	{
		this.workExperience = workExperience;
	}

	public String getName()
	{
		return name;
	}

	public void setName(String name)
	{
		this.name = name;
	}

	public int getAge()
	{
		return age;
	}

	public void setAge(int age)
	{
		this.age = age;
	}
	
	public Object clone()
	{
		Resume r = null;
		try
		{
			r= (Resume)super.clone();
			r.setWorkExperience((WorkExperience)workExperience.clone()); //通过拷贝设置工作经验
			return r;
		}
		catch (CloneNotSupportedException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null ;
		}
	}
	
}

   运行测试:

  同运行测试2中的代码相同

  

public class ProtoType
{
	public static void main (String args[])
	{
		WorkExperience we = new WorkExperience("公司A", 2);
		
		Resume r1 = new Resume(we, "小张", 24);
		
		Resume r2= (Resume)r1.clone() ;
		
		r2.setName("小李");
		r2.setAge(30);
		r2.getWorkExperience().setCompanyName("公司B");
		r2.getWorkExperience().setYears(3);
		
		System.out.println(r1.getName()+r1.getAge()+"岁,工作经验"+r1.getWorkExperience().getCompanyName()+","+r1.getWorkExperience().getYears()+"年");
		System.out.println(r2.getName()+r2.getAge()+"岁,工作经验"+r2.getWorkExperience().getCompanyName()+","+r2.getWorkExperience().getYears()+"年");
		
	}
}

  运行结果

小张24岁,工作经验公司A,2年
小李30岁,工作经验公司B,3年

  r2修改工作经验后没有影响r1.

 

总结:

  原型模式主要用到的技术就是克隆,这样如果是在创建对象比较费时是可以提高程序的效率;

  深拷贝相对于浅拷贝来说要花费更多的内存开销,具体使用那种拷贝方式可以视情况而定;

  深拷贝和浅拷贝可以结合使用(延迟拷贝)这样既可以提高效率也可以进行深拷贝。

  

 

 

  

  

 

  

 

 

  

 

 

 

    

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。