设计模式-原型模式(浅拷贝、深拷贝)、java代码案例以及在JDK类库中的应用

原型模式

定义

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

结构

1.抽象原型类(prototype):实现cloneable接口,并重写clone()方法。

2.具体原型类:实现一个克隆自身的操作。

类图

Prortotype类

package com.headfirst.prototypemode.interfaces;

/**
 *	1.实现Cloneable接口
 *  2.重写clone()方法
 */
public class IPrototype implements Cloneable {

	public String id;
	public String name;
	@Override
	protected IPrototype clone() {
		IPrototype clone = null;
		try {
			clone = (IPrototype) super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return clone;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
}

测试类

	public static void main(String[] args) {
		IPrototype iPrototype = new IPrototype();
		iPrototype.setId("1");
		iPrototype.setName("lisi");
		IPrototype clone = iPrototype.clone();
		clone.setId("2");
		clone.setName("wangwu");
		System.out.println(iPrototype.getName());//lisi
		System.out.println(clone.getName());//wangwu
		System.out.println(iPrototype == clone);//false
	}

 

浅拷贝与深拷贝的区别

浅拷贝

抽象原型类

package com.headfirst.prototypemode.interfaces;

import java.util.ArrayList;

/**
 *	1.实现Cloneable接口
 *  2.重写clone()方法
 *  3.成员变量为集合类型
 */
public class IPrototype implements Cloneable {

	public ArrayList<String> list = new ArrayList<String>();
	@Override
	protected IPrototype clone() {
		IPrototype clone = null;
		try {
			clone = (IPrototype) super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return clone;
	}
	public ArrayList<String> getList() {
		return list;
	}
	public void setList(ArrayList<String> list) {
		this.list = list;
	}
	public void display(){
		for (String str:list) {
			System.out.print(str+",");
		}
		System.out.println();
	}
	
}

测试类

	public static void main(String[] args) {
		IPrototype iPrototype = new IPrototype();
		IPrototype clone = iPrototype.clone();
		iPrototype.getList().add("tmp1");
		iPrototype.display();//tmp1,
		clone.getList().add("tmp2");
		iPrototype.display();//tmp1,tmp2,
		clone.display();//tmp1,tmp2,
                System.out.println(iPrototype.getList() == clone.getList());//true
	}

通过打印的结果不难发现,iPrototype和clone中的list操作的是同一个对象,打印出来都是tmp1,tmp2,这是因为IPrototype中的list为引用类型,浅拷贝只能克隆基本数据类型,而是无法克隆引用数据类型,这就是浅拷贝

那么怎么办?深拷贝就是将指定的引用数据类型再克隆一份。

 

深拷贝

IPrototype类

package com.headfirst.prototypemode.interfaces;

import java.util.ArrayList;

/**
 *	1.实现Cloneable接口
 *  2.重写clone()方法
 *  3.成员变量为集合类型
 */
public class IPrototype implements Cloneable {

	public ArrayList<String> list = new ArrayList<String>();
	@Override
	protected IPrototype clone() {
		IPrototype clone = null;
		try {
			clone = (IPrototype) super.clone();
			clone.list = (ArrayList<String>) this.list.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return clone;
	}
	public ArrayList<String> getList() {
		return list;
	}
	public void setList(ArrayList<String> list) {
		this.list = list;
	}
	public void display(){
		for (String str:list) {
			System.out.print(str+",");
		}
		System.out.println();
	}

}

测试类

	public static void main(String[] args) {
		IPrototype iPrototype = new IPrototype();
		IPrototype clone = iPrototype.clone();
		iPrototype.getList().add("tmp1");
		iPrototype.display();//tmp1,
		clone.getList().add("tmp2");
		iPrototype.display();//tmp1,
		clone.display();//tmp2,
		System.out.println(iPrototype.getList() == clone.getList());//false
	}

由于浅拷贝无法克隆引用数据类型,所以需要对这里的list先克隆一份,再将它指向iPrototype.list,注意一点,这里的ArrayList本身就已经实现了Cloneable接口(看源码),所以这里换成自定义类,首先这个类需要先实现Cloneable接口。

从结果可以看出Prototype.getList() == clone.getList()返回结果为false,所以这里的list不会互相影响。

优点

1.提高性能。

2.避免复杂的构造函数

缺点

1.必须实现Cloneable接口

2.对于已有的对象需要增加clone方法,这违背了OCP开放封闭原则

总结

原型模式主要用于对象的复制,它的核心是就是类图中的原型类Prototype。Prototype类需要具备以下两个条件: 
  (1)实现Cloneable接口。在java语言有一个Cloneable接口,它的作用只有一个,就是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法。在java虚拟机中,只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出CloneNotSupportedException异常。 
  (2)重写Object类中的clone方法。Java中,所有类的父类都是Object类,Object类中有一个clone方法,作用是返回对象的一个拷贝,但是其作用域protected类型的,一般的类无法调用,因此Prototype类需要将clone方法的作用域修改为public类型。

JDK类库中的原型模式

java.util.ArrayList<E>

    /**
     * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The
     * elements themselves are not copied.)
     *
     * @return a clone of this <tt>ArrayList</tt> instance
     */
    public Object clone() {
        try {
            @SuppressWarnings("unchecked")
                ArrayList<E> v = (ArrayList<E>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError();
        }
    }

java.util.HashSet<E>

    /**
     * Returns a shallow copy of this <tt>HashSet</tt> instance: the elements
     * themselves are not cloned.
     *
     * @return a shallow copy of this set
     */
    public Object clone() {
        try {
            HashSet<E> newSet = (HashSet<E>) super.clone();
            newSet.map = (HashMap<E, Object>) map.clone();
            return newSet;
        } catch (CloneNotSupportedException e) {
            throw new InternalError();
        }
    }

java.util.HashMap

    /**
     * Returns a shallow copy of this <tt>HashMap</tt> instance: the keys and
     * values themselves are not cloned.
     *
     * @return a shallow copy of this map
     */
    public Object clone() {
        HashMap<K,V> result = null;
        try {
            result = (HashMap<K,V>)super.clone();
        } catch (CloneNotSupportedException e) {
            // assert false;
        }
        if (result.table != EMPTY_TABLE) {
            result.inflateTable(Math.min(
                (int) Math.min(
                    size * Math.min(1 / loadFactor, 4.0f),
                    // we have limits...
                    HashMap.MAXIMUM_CAPACITY),
               table.length));
        }
        result.entrySet = null;
        result.modCount = 0;
        result.size = 0;
        result.init();
        result.putAllForCreate(this);

        return result;
    }

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值