java语言实现创建型设计模式—原型模式(Prototype)

来源:互联网 发布:已备案过期删除域名 编辑:程序博客网 时间:2024/06/16 09:34

一、描述

原型模式是通过一个原型对象来标明要创建的对象的类型,然后用复制这个原型对象的方法来拷贝创建更多的同类型对象。例如我们在程序的动态运行过程中有了一个对象,这个对象中包含了一系列的有效数据,我们此时需要一个和该对象完全相同的新对象,并且在拷贝之后,新旧对象之间没有任何联系,对任何一个对象的更改都不影响另一个对象。

在java中所有类都默认继承自java.lang.Object类,在这个Object类中有一个clone()方法,该方法将返回Object对象的一个拷贝。

我们让需要被拷贝的类实现 Cloneable 接口,该接口用来指示Object.clone()方法可以合法地对该类实例进行按字段复制。如果在没有实现Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出CloneNotSupportedException 异常。


注意Cloneable接口是一个标记接口,该接口中没有任何别的方法,只是作为标记来标明这个类可以合法的使用Object类的clone()方法来产生该实例的一个副本。

除了Cloneable接口是标记接口之外还有Serializable接口(用于类启用其序列化功能,未实现此接口的类将无法使其任何状态序列化或反序列化)、RandomAccess接口List 实现中所使用的标记接口,用来表明其支持快速(通常是固定时间)随机访问,从而在将其应用到随机或连续访问列表时能提供良好的性能)、Remote接口Remote 接口用于标识其方法可以从非本地虚拟机上调用的接口。任何远程对象都必须直接或间接实现此接口。只有在“远程接口(扩展java.rmi.Remote 的接口)中指定的这些方法才可远程使用,实现类可以实现任意数量的远程接口,并且可以扩展其他远程实现类。RMI 提供一些远程对象实现可以扩展的有用类,这些类便于远程对象创建)。


二、原型设计模式的优缺点

优点:在原型模式中,可以动态地添加产品类,而且不会对整天结构产生影响,只是复制了一个对象而已。

缺点:由于原型模式要让每个类实现Cloneable 接口,并重写Object类中的clone()方法,而且原型模式在实现深拷贝的时候需要补充更多的代码,这无疑增加了一定的代码量。


三、源代码

3.1 浅拷贝:如果待拷贝的对象中存在对象类型和引用类型,那么只拷贝对象和引用类型的地址,而是真正拷贝对象和引用中的数据。

package tong.day5_1.dogCase;import java.util.ArrayList;/** * DogClone实现了Cloneable接口,重写clone()方法,调用父类的clone()拷贝一个对象并返回,Dog类并没有clone()方法,这是浅拷贝的模式。 * 浅拷贝:基本数据类型确实另外拷贝了一个副本,但是对于对象类型和引用类型则只拷贝对象或引用的地址, * 导致拷贝的对象中的对象类型的引用指向同一个对象,只要有一个修改了,就会影响另一个对象中的数据。 * @author tong * */public class ShallowClone {public static void main(String[] args) { //拷贝之前数据的值DogClone dogClone = new DogClone();System.out.println("原来的dogClone.basicCount="+dogClone.basicCount);System.out.println("原来的dogClone.dog="+dogClone.dog);System.out.println("原来的dogClone.arraylist="+dogClone.arrayList);DogClone dogClone2 = (DogClone) dogClone.clone();System.out.println("-----------------------");//对拷贝的对象中的对象类型和引用类型的数据进行变更,则会影响另一个对象的数据;基本类型是进行值拷贝所以产生另一个副本,对原数据不会有影响dogClone2.basicCount = 2;Dog dog = dogClone2.dog;dog.changeCount();dogClone2.arrayList.add("java");//原对象中的基本数据类型的值不变System.out.println("后来的dogClone.basicCount="+dogClone.basicCount);System.out.println("后来的dogClone.dog="+dogClone.dog);System.out.println("后来的dogClone.arrayList="+dogClone.arrayList);System.out.println("dogClone2.basicCount="+dogClone2.basicCount);System.out.println("dogClone2.dog="+dogClone2.dog);System.out.println("dogClone2.arrayList="+dogClone2.arrayList);}}class Dog{public int legCount;public Dog(int legCount) {this.legCount = legCount;}public void changeCount() {this.legCount +=5;}//重写Dog类的toString()方法,在输出dog对象时调用该方法@Overridepublic String toString() {return Integer.toString(legCount);}}//DogClone实现了Cloneable接口,只要重写Object中的clone()即可根据自己的需要拷贝对象class DogClone implements Cloneable{//基本数据类型拷贝时会直接拷贝数据值的一个副本,也就是说拷贝后产生的legCount数值和原来被拷贝的值没有任何关系public int basicCount;//Dog对象类型,在使用浅拷贝的时候,拷贝的是栈中对象的地址,而不是对象地址所指向的堆内存的真实数据public Dog dog = new Dog(5);//ArrayList引用类型,在浅拷贝时,只拷贝引用的地址,而不是拷贝引用所指向的堆内存中的字符串public ArrayList<String> arrayList = new ArrayList<String>();public DogClone() {basicCount = 4;arrayList.add("hello");arrayList.add("world");}//重写了clone()返回一个DogClone类的副本对象@Overrideprotected Object clone(){DogClone dogClone = null;try {dogClone =  (DogClone) super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return dogClone;}}
运行结果:

浅拷贝


3.2 深拷贝:DogClone实现了Cloneable接口,重写clone()方法,调用父类的clone()拷贝一个对象,并显式调用dog对象和arrayList对象的拷贝方法返回该类对象,这样拷贝产生的对象和原来的对象就互不干扰,相互独立。

package tong.day5_1.deepClone;import java.util.ArrayList;/** * DogClone实现了Cloneable接口,重写clone()方法,调用父类的clone()拷贝一个对象,并显式调用dog对象和arrayList对象的拷贝方法返回该类对象,这是深拷贝的模式。 * 深拷贝:基本数据类型确实另外拷贝了一个副本,但是对于对象类型和引用类型则默认的是只拷贝对象或引用的地址, * 如果想要使这两种类型也拷贝对象和引用中的数据,那么就需要在重写的clone()方法中显式地调用该对象或者引用类型的clone()方法。 * 所以我们需要让Dog类实现Cloneable接口使其具有拷贝能力,ArrayList间接继承了Object接口,本身就有clone()方法。 * @author tong * */public class DeepClone {public static void main(String[] args) {// 拷贝之前数据的值DogClone dogClone = new DogClone();System.out.println("原来的dogClone.basicCount=" + dogClone.basicCount);System.out.println("原来的dogClone.dog=" + dogClone.dog);System.out.println("原来的dogClone.arraylist=" + dogClone.arrayList);DogClone dogClone2 = (DogClone) dogClone.clone();System.out.println("-----------------------");// 这里进行的是深拷贝,对拷贝的对象中的对象类型和引用类型的数据进行变更,不会影响另一个对象的数据;基本类型是进行值拷贝所以产生另一个副本,对原数据也不会有影响dogClone2.basicCount = 2;Dog dog = dogClone2.dog;dog.changeCount();dogClone2.arrayList.add("java");// 原对象中所有数据的值都不变System.out.println("后来的dogClone.basicCount=" + dogClone.basicCount);System.out.println("后来的dogClone.dog=" + dogClone.dog);System.out.println("后来的dogClone.arrayList=" + dogClone.arrayList);System.out.println("dogClone2.basicCount=" + dogClone2.basicCount);System.out.println("dogClone2.dog=" + dogClone2.dog);System.out.println("dogClone2.arrayList=" + dogClone2.arrayList);}}//为了实现深拷贝,我们让Dog类实现Cloneable接口并重写该接口中的clone()方法class Dog implements Cloneable {public int legCount;public Dog(int legCount) {this.legCount = legCount;}public void changeCount() {this.legCount += 5;}// 重写Dog类的toString()方法,在输出dog对象时调用该方法@Overridepublic String toString() {return Integer.toString(legCount);}//重写clone()方法,使其dog对象具有自我复制的能力@Overrideprotected Object clone() {Dog dog = null;try {dog = (Dog) super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return dog;}}////为了进行DogClone对象的拷贝,我们让DogClone类实现Cloneable接口并重写重写Object中的clone()方法class DogClone implements Cloneable {// 基本数据类型拷贝时会直接拷贝数据值的一个副本,也就是说拷贝后产生的legCount数值和原来被拷贝的值没有任何关系public int basicCount;// Dog对象类型,在使用浅拷贝的时候,拷贝的是栈中对象的地址,而不是对象地址所指向的堆内存的真实数据public Dog dog = new Dog(5);// ArrayList引用类型,在浅拷贝时,只拷贝引用的地址,而不是拷贝引用所指向的堆内存中的字符串public ArrayList<String> arrayList = new ArrayList<String>();public DogClone() {basicCount = 4;arrayList.add("hello");arrayList.add("world");}//重写了clone()返回一个DogClone类的副本对象@Overrideprotected Object clone() {DogClone dogClone = null;try {dogClone = (DogClone) super.clone();} catch (CloneNotSupportedException e) {// TODO Auto-generated catch blocke.printStackTrace();}//显式调用dog对象的clone()返回一个dog对象的副本dogClone.dog = (Dog) dog.clone();//显式调用arrayList对象的clone()返回一个arrayList对象的副本dogClone.arrayList = (ArrayList<String>) arrayList.clone();return dogClone;}}
运行结果:

深拷贝



0 0
原创粉丝点击