创建型模式--原型模式

 概述
    用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
 适用性
    1.当一个系统应该独立于它的产品创建、构成和表示时。

    2.当要实例化的类是在运行时刻指定时,例如,通过动态装载。

    3.为了避免创建一个与产品类层次平行的工厂类层次时。

    4.当一个类的实例只能有几个不同状态组合中的一种时。

    建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。
			
 参与者
    1. Prototype
       声明一个克隆自身的接口。

    2. ConcretePrototype
       实现一个克隆自身的操作。

    3. Client
       让一个原型克隆自身从而创建一个新的对象。

类图:
                                                                




代码描述:

<span style="font-size:18px;">public class Prototype implements Cloneable{
	private String name;
	private String[] names=new String[]{};
    public void setName(String name) {
        this.name = name;
    }
    
    public String getName() {
        return this.name;
    }
    
    public String[] getNames() {
		return names;
	}

	public void setNames(String[] names) {
		this.names = names;
	}

	public Object clone(){
        try {
            return super.clone();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

}</span>


<span style="font-size:18px;">public class ConcretePrototype extends Prototype{
	public ConcretePrototype(String name,String[] names) {
        setName(name);
        setNames(names);
    }

}</span>


<span style="font-size:18px;">public class Test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Prototype pro = new ConcretePrototype("prototype",new String[]{"prototype"});
		System.out.println("----克隆前(pro)----\nname:"+pro.getName()+"\nnanmes:"+pro.getNames()[0]);
        Prototype pro2 = (Prototype)pro.clone();
        pro2.setName("pro2");
        String[] pr=pro2.getNames();
        pr[0]="pro2";
        pro2.setNames(pr);
        System.out.println("----克隆后(pro)----\nname:"+pro.getName()+"\nnanmes:"+pro.getNames()[0]);
        System.out.println("----克隆后(pro2)----\nname:"+pro2.getName()+"\nnanmes:"+pro2.getNames()[0]);
	}

}</span>


运行结果:
                                                               

从上面我们实现了克隆,但我们发现克隆前的pro的names数组克隆后赋值给pro2后,在pro2中更改names数组,打印

pro的name数组的值后,name变为了之前在pro2中更改的值了。在这里就涉及到了浅拷贝和深拷贝了。

那什么是浅拷贝和深拷贝?这里做个介绍:

浅拷贝:对值类型的成员变量进行值的复制,对引用类型的成员变量只复制引用,不复制引用的对象

深拷贝:对值类型的成员变量进行值的复制,对引用类型的成员变量也进行引用对象的复制


也就是说在上述只做了浅拷贝

如下图:


                                                                                   


在下述实现深拷贝


利用序列化实现深度拷贝

        把对象写到流里的过程是序列化(Serialization)过程;而把对象从流中读出来的过程则叫反序列化(Deserialization)过程。应当指出的是,写到流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。

     Java语言里深度克隆一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的拷贝)写到一个流里(序列化),再从流里读回来(反序列化),便可以重建对象。


<span style="font-size:18px;">public class Prototype implements Serializable{
	private String name;
	private String[] names=new String[]{};
    public void setName(String name) {
        this.name = name;
    }
    
    public String getName() {
        return this.name;
    }
    
    public String[] getNames() {
		return names;
	}

	public void setNames(String[] names) {
		this.names = names;
	}

	public Object clone(){
        try {
            return super.clone();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

}</span>

<span style="font-size:18px;">public class ConcretePrototype extends Prototype{
	public ConcretePrototype(String name,String[] names) {
        setName(name);
        setNames(names);
    }

}</span>

<span style="font-size:18px;">public class Test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Test test=new Test();
		Prototype pro = new ConcretePrototype("prototype",new String[]{"prototype"});
		System.out.println("----克隆前(pro)----\nname:"+pro.getName()+"\nnanmes:"+pro.getNames()[0]);
        Prototype pro2 = (Prototype) test.proClone(pro);
        pro2.setName("pro2");
        String[] pr=pro2.getNames();
        pr[0]="pro2";
        pro2.setNames(pr);
        System.out.println("----克隆后(pro)----\nname:"+pro.getName()+"\nnanmes:"+pro.getNames()[0]);
        System.out.println("----克隆后(pro2)----\nname:"+pro2.getName()+"\nnanmes:"+pro2.getNames()[0]);
	}
	 public Object proClone(Object src)  
	    {  
	        Object o = null;  
	        try  
	        {  
	            if (src != null)  
	            {  
	            	// 将对象写到流里 
	                ByteArrayOutputStream baos =new ByteArrayOutputStream();  
	                ObjectOutputStream oos = new ObjectOutputStream(baos);  
	                oos.writeObject(src);  
	                oos.close();  
	                // 将对象从流里读出来 
	                ByteArrayInputStream bais = new ByteArrayInputStream(baos  
	                        .toByteArray());  
	                ObjectInputStream ois = new ObjectInputStream(bais);  
	                o = ois.readObject();  
	                ois.close();  
	            }  
	        } catch (IOException e)  
	        {  
	            e.printStackTrace();  
	        } catch (ClassNotFoundException e)  
	        {  
	            e.printStackTrace();  
	        }  
	        return o;  
	    }
}</span>

运行结果:

                               


原理图:

                         


转载请注明出处:http://blog.csdn.net/hai_qing_xu_kong/article/details/42109245    情绪控_




©️2020 CSDN 皮肤主题: 猿与汪的秘密 设计师:上身试试 返回首页