• Java设计模式---原型模式(Prototype)


    1.  原型模式(Prototype)定义:

         用原型实例指定创建对象的种类,并且通过拷贝这些原型得到行的实例

    2.  实现方式:    

    • 实现Cloneable接口。在java语言有一个Cloneable接口,它的作用只有一个,就是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法。在java虚拟机中,只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出CloneNotSupportedException异常。
    • 重写Object类中的clone方法。Java中,所有类的父类都是Object类,Object类中有一个clone方法,作用是返回对象的一个拷贝,但是其作用域protected类型的,一般的类无法调用,因此,Prototype类需要将clone方法的作用域修改为public类型。
    3. 原型模式的注释事项:

          1.  构造方法不会执行

           一个实现了Cloneable并重写了clone方法的类A,有一个无参构造或有参构造B,通过new关键字产生了一个对象S,再然后通过S.clone()方式产生了一个新的对象T,那么在对象拷贝时构造函数B是不会被执行的。因为Object类的clone方法的原理是从内存中(具体的说就       是堆内存)以二进制流的方式进行拷贝,重新分配一个内存块。

          2.  浅复制与深复制    

       浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的,所以浅复制是不安全的(如果原来的实例被修改,那么新的实例也会跟着变化或者复制产生的实例被修改,原实例会发生变化)。

                  对于浅复制: 类引用的成员变量必须满足两个条件才不会被拷贝:1.是类的成员变量而不是方法内变量;2必须是一个可变的引用对象,而不是一个原始类型或者不可变对象(包括int、long、char等及其对象类型[Integer、Long]、String)

       深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。

     4. 浅复制与深复制的示例代码:

        辅助User类

    public class User implements Serializable{
       
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1L;
    	
    	private String username;
    	private String phone;
    	
    	
    	public User(String username,String phone){
    		this.username=username;
    		this.phone=phone;
    	}
    	
    	public String getUsername() {
    		return username;
    	}
    	public void setUsername(String username) {
    		this.username = username;
    	}
    	public String getPhone() {
    		return phone;
    	}
    	public void setPhone(String phone) {
    		this.phone = phone;
    	}
    			
    }
    原型类:

    public class Prototype implements Cloneable ,Serializable{
        
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1L;
    	private String str;
        private User user;
        
    	public User getUser() {
    		return user;
    	}
    
    	public void setUser(User user) {
    		this.user = user;
    	}
    
    	public String getStr() {
    		return str;
    	}
    
    	public void setStr(String str) {
    		this.str = str;
    	}
    	
    	/* 
    	 * 浅复制
    	 */
    	@Override
    	public Object clone() throws CloneNotSupportedException {
    		Prototype up=(Prototype) super.clone();
    		return up;
    	}
    	
    	/**
    	 * 深复制
    	 * @return
    	 * @throws IOException
    	 * @throws ClassNotFoundException
    	 */
    	public Object deepClone() throws IOException, ClassNotFoundException{
    		/* 写入当前对象的二进制流 */
    		ByteArrayOutputStream bos=new ByteArrayOutputStream();
    		ObjectOutputStream oos=new ObjectOutputStream(bos);
    		oos.writeObject(this);
    		
    		/* 读出当前对象的二进制流  */
    		ByteArrayInputStream bis=new ByteArrayInputStream(bos.toByteArray());
    		ObjectInputStream ois=new ObjectInputStream(bis);
    		Object obj=ois.readObject();
    		return obj;
    	}
    	
    	public static void main(String[] args) {
    		Prototype obj=new Prototype();
    		User user=new User("aaaa", "13321352222");
    		obj.setStr("原型模式");
    		obj.setUser(user);
    		try {
    			//浅复制对象
    			System.out.println("浅克隆前的obj-user的username为:"+obj.getUser().getUsername());
    			
    			Prototype copyObj=(Prototype) obj.clone();
    			
    			System.out.println("浅克隆后的obj-user的username为:"+obj.getUser().getUsername());
    
    			System.out.println("浅克隆后的copyObj-user的username为:"+copyObj.getUser().getUsername());
    	
    			user.setUsername("vvvv");
    			
    			System.out.println("浅克隆后修改user后obj的username为:"+obj.getUser().getUsername());
    		
    			System.out.println("浅克隆后修改user后copyObj的username为:"+copyObj.getUser().getUsername());
    			
    			//深复制对象
    			Prototype deepCopyObj=(Prototype) obj.deepClone();
    			
    			System.out.println("深克隆后deepCopyObj的username为:"+deepCopyObj.getUser().getUsername());
    			
    			user.setUsername("pppp");
    			
    			System.out.println("深隆后修改user后deepCopyObj的username为:"+deepCopyObj.getUser().getUsername());
    			
    			System.out.println("深隆后修改user后obj的username为:"+obj.getUser().getUsername());
    			
    		} catch (CloneNotSupportedException e) {
    			
    			e.printStackTrace();
    			
    		} catch (ClassNotFoundException e) {
    			
    			e.printStackTrace();
    			
    		} catch (IOException e) {
    			
    			e.printStackTrace();
    			
    		}
    	}
    
    }
    测试结果:

    浅克隆前的obj-user的username为:aaaa
    浅克隆后的obj-user的username为:aaaa
    浅克隆后的copyObj-user的username为:aaaa
    浅克隆后修改user后obj的username为:vvvv
    浅克隆后修改user后copyObj的username为:vvvv
    深克隆后deepCopyObj的username为:vvvv
    深隆后修改user后deepCopyObj的username为:vvvv
    深隆后修改user后obj的username为:pppp
    结果分析:

    从结果来看,浅复制之后修改了user的内容,2个对象都发生了变化,而深复制之后修改user,只是原对象发生了改变,复制产生的对象并没有发生变化。所以这也验证了:Object类提供的方法clone只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址
    上述代码中的深复制通过读取序列化后的对象二进制流的方式实现,所以User类和原型类均实现了Serializable接口

    5. 原型模式的优点:

    原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好的体现其优点。


      

  • 相关阅读:
    Tensorflow 搭建自己的神经网络(二)
    Tensorflow 搭建自己的神经网络(一)
    JSON简介
    JS 弹出框计时器
    【扫盲】史上最全的互联网专业词语汇总,小白必备,人手一套!
    推荐几个数据分析网站
    转:一位阿里人对数据模型建设的几点思考与总结
    数据模型设计心得
    数据仓库架构设计
    数据仓库建模与ETL的实践技巧(转载)
  • 原文地址:https://www.cnblogs.com/elgin-seth/p/5293771.html
Copyright © 2020-2023  润新知