原型模式 浅复制与深复制

原型模式(Prototype): 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

这里我用Java来给大家介绍一下它的基础使用。

基础示例

说明:在Java中自定义类的对象可以被复制,自定义类就必须实现Cloneable中的clone()方法,而在.NET中便是实现ICloneable接口其中的唯一方法Clone()方法

原型类

public abstract class Prototype implements Cloneable{
         
	private  String id;

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}
	
	
	public abstract Prototype Clone() throws CloneNotSupportedException;
}

具体原型类:

public class ConcretePrototype1 extends Prototype {
	private String id;
	
	public ConcretePrototype1(String id){
		this.id = id;
	}
	
	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}


	@Override
	public Prototype Clone() throws CloneNotSupportedException {
		
		return (Prototype) this.clone();
	}

}

客户端代码:

public class UserCilent {

	public static void main(String[] args) throws CloneNotSupportedException {
          ConcretePrototype1 c1 = new ConcretePrototype1("clonedId");
          ConcretePrototype1 c2 = (ConcretePrototype1) c1.Clone();
          System.out.println("Cloned id: " + c2.getId());
	           }
       }

结果显示:

Cloned id: clonedId

 

总结:

1, 原型模式其实是从一个对象再创建另外一个可定制的对象,而且不需要知道其中的具体创建细节,在性能方面,它比传统的           new一个新对象消耗的资源更小。

2, 在不同语言中具体的类的复制需要实现cloneable接口其中的clone()方法才可以进行对象克隆

 

浅复制与深复制

在clone方法中,(有的编程语言是MemberwiseClone())  : 如果字段是值类型的。则对该字段执行逐位复制,如果字段是引用类型,则只复制引用但不复制引用对象;因此,元素对象及其复本引用同一个对象。具体什么意思呢?在下面的员工类中包含一个部门对象的引用,如果对员工使用clone()方法,只会有里面部门对象引用,而不包含具体的部门对象字段信息。

 

浅复制

部门类

public class Dept  {
         private String deptno; //部门号
         private String dName; //部门名称
         
		public String getDeptno() {
			return deptno;
		}
		public void setDeptno(String deptno) {
			this.deptno = deptno;
		}
		public String getdName() {
			return dName;
		}
		public void setdName(String dName) {
			this.dName = dName;
		}
         
}

员工类

public class Emp implements Cloneable{
        private String ename; //用户名
        private String job;
        private String sal;
        
        private Dept dept;
        
        public Emp(String ename){
        	this.ename = ename;
        	dept = new Dept(); //在 员工实例化时也要实例化部门
        }
        
       

		public void setJobInfo(String job,String sal) {
			this.job = job;
			this.sal = sal;
		}


		public void setDept(String deptno,String dName) {
			dept.setDeptno(deptno);
			dept.setdName(dName);
		}
        
		public void Display(){
			System.out.println("姓名: " + ename +" ,工作: "+ job + " ,薪水: " +sal);
			System.out.println("部门信息: " + dept.getDeptno() + " , " + dept.getdName());
		}
        
		public Emp Clone(){
			try {
				return (Emp) this.clone();
			} catch (CloneNotSupportedException e) {
				e.printStackTrace();
			}
			return null;
		}
}

客户端调用:

public static void main(String[] args) throws CloneNotSupportedException {
        Emp emp = new Emp1("张三");
  		emp.setJobInfo("文员", "5000");
  		emp.setDept("10", "行政部");
  		
  		Emp e2 = emp.Clone();
  		e2.setDept("20", "人力资源部");
  		
  		Emp e3 = emp.Clone();
  		e3.setJobInfo("应用开发工程师", "8000");
  		e3.setDept("30", "信息部");
  		
  		emp.Display();
  		e2.Display();
  		e3.Display();
	}

结果显示:

姓名: 张三 ,工作: 文员 ,薪水: 5000
部门信息: 30 , 信息部
姓名: 张三 ,工作: 文员 ,薪水: 5000
部门信息: 30 , 信息部
姓名: 张三 ,工作: 应用开发工程师 ,薪水: 8000
部门信息: 30 , 信息部

浅复制总结:通过结果发现,虽然给emp,e2,e3这三个对象的部门引用设置了不同的部门信息,但是这三个引用都指向最后的那个dept对象。这就叫“浅复制”,被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。

 

深复制:

深复制把引用对象的变量指向复制过的新对象,而不是原来的被引用的对象

部门类:多了一个clone()方法,使得该对象的引用实际是每个字段值复制而已。

public class Dept implements Cloneable {
         private String deptno; //部门号
         private String dName; //部门名称
         
		public String getDeptno() {
			return deptno;
		}
		public void setDeptno(String deptno) {
			this.deptno = deptno;
		}
		public String getdName() {
			return dName;
		}
		public void setdName(String dName) {
			this.dName = dName;
		}
         
        public  Dept Clone(){
        	try {
				return (Dept) this.clone();
			} catch (CloneNotSupportedException e) {
				e.printStackTrace();
			}
			return null;
        }; 
}

员工类:与浅复制区别在于,内部的引用对象用的是clone方法,而自身的clone方法实际是new一个对象

public class Emp implements Cloneable{
        private String ename; //用户名
        private String job;
        private String sal;
        
        private Dept dept;
        
        public Emp(String ename){
        	this.ename = ename;
        	dept = new Dept(); //在 员工实例化时也要实例化部门
        }
        
        private Emp(Dept dept){
          	this.dept = dept.Clone();
        }
        

		public void setJobInfo(String job,String sal) {
			this.job = job;
			this.sal = sal;
		}


		public void setDept(String deptno,String dName) {
			dept.setDeptno(deptno);
			dept.setdName(dName);
		}
        
		public void Display(){
			System.out.println("姓名: " + ename +" ,工作: "+ job + " ,薪水: " +sal);
			System.out.println("部门信息: " + dept.getDeptno() + " , " + dept.getdName());
		}
        
		public Emp Clone(){
			Emp emp = new Emp(this.dept);
			emp.ename = this.ename;
			emp.job = this.job;
			emp.sal = this.sal;
			return emp;
		}
}

客户端代码:

public static void main(String[] args) throws CloneNotSupportedException {
        Emp emp = new Emp("张三");
  		emp.setJobInfo("文员", "5000");
  		emp.setDept("10", "行政部");
  		
  		Emp e2 = emp.Clone();
  		e2.setDept("20", "人力资源部");
  		
  		Emp e3 = emp.Clone();
  		e3.setJobInfo("应用开发工程师", "8000");
  		e3.setDept("30", "信息部");
  		
  		emp.Display();
  		e2.Display();
  		e3.Display();
	}

结果显示:

姓名: 张三 ,工作: 文员 ,薪水: 5000
部门信息: 10 , 行政部
姓名: 张三 ,工作: 文员 ,薪水: 5000
部门信息: 20 , 人力资源部
姓名: 张三 ,工作: 应用开发工程师 ,薪水: 8000
部门信息: 30 , 信息部

深复制总结:发现深复制也是把最底层的对象引用使用了clone()方法。而外层选择的是new 一个对象的处理,在性能方面只是优化了最底层的资源消耗,并非是层层优化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值