程序员人生 网站导航

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

栏目:框架设计时间:2015-05-06 08:47:40

1、描写

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

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

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


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

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


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

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

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


3、源代码

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

package tong.day5_1.dogCase; import java.util.ArrayList; /** * DogClone实现了Cloneable接口,重写clone()方法,调用父类的clone()拷贝1个对象并返回,Dog类并没有clone()方法,这是浅拷贝的模式。 * 浅拷贝:基本数据类型确切另外拷贝了1个副本,但是对对象类型和援用类型则只拷贝对象或援用的地址, * 致使拷贝的对象中的对象类型的援用指向同1个对象,只要有1个修改了,就会影响另外一个对象中的数据。 * @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对象时调用该方法 @Override public String toString() { return Integer.toString(legCount); } } //DogClone实现了Cloneable接口,只要重写Object中的clone()便可根据自己的需要拷贝对象 class DogClone implements Cloneable{ //基本数据类型拷贝时会直接拷贝数据值的1个副本,也就是说拷贝后产生的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()返回1个DogClone类的副本对象 @Override protected Object clone(){ DogClone dogClone = null; try { dogClone = (DogClone) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return dogClone; } }
运行结果:

浅拷贝


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

package tong.day5_1.deepClone; import java.util.ArrayList; /** * DogClone实现了Cloneable接口,重写clone()方法,调用父类的clone()拷贝1个对象,并显式调用dog对象和arrayList对象的拷贝方法返回该类对象,这是深拷贝的模式。 * 深拷贝:基本数据类型确切另外拷贝了1个副本,但是对对象类型和援用类型则默许的是只拷贝对象或援用的地址, * 如果想要使这两种类型也拷贝对象和援用中的数据,那末就需要在重写的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对象时调用该方法 @Override public String toString() { return Integer.toString(legCount); } //重写clone()方法,使其dog对象具有自我复制的能力 @Override protected 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 { // 基本数据类型拷贝时会直接拷贝数据值的1个副本,也就是说拷贝后产生的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()返回1个DogClone类的副本对象 @Override protected Object clone() { DogClone dogClone = null; try { dogClone = (DogClone) super.clone(); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //显式调用dog对象的clone()返回1个dog对象的副本 dogClone.dog = (Dog) dog.clone(); //显式调用arrayList对象的clone()返回1个arrayList对象的副本 dogClone.arrayList = (ArrayList<String>) arrayList.clone(); return dogClone; } }
运行结果:

深拷贝



------分隔线----------------------------
------分隔线----------------------------

最新技术推荐