欢迎来到山村网

浅谈Java设计模式关于原型模式(Prototype)思索建议

2019-03-02 09:59:35浏览:184 来源:山村网   
核心摘要:java教程:关于Java设计模式关于原型模式(Prototype) IT信息技术http://www.52ij.com/jishu/首先需要弄清楚什么叫原型模式,或者

java教程:关于Java设计模式关于原型模式(Prototype) IT信息技术http://www.52ij.com/jishu/


浅谈Java设计模式关于原型模式(Prototype)思索建议 山村


首先需要弄清楚什么叫原型模式,或者说为什么要有原型模式,运用它会给我们带来什么或能解决什么问题?原型模式(Prototype)同抽象工厂模式同属于创建型模式,它主要关注于大量相同或相似对象的创建问题,应用原型模式就是先需要一个原对象,然后通过对原对象进行复制(克隆),来产生一个与原对象相同或相似的新对象。注意这里所说的对象相同不是指复制出来的副本对象与原对象是同一个对象,相反复制出来的副本对象必须和原对象是两个不同的对象,只是两个对象的内容相同。

我们在编程过程中,经常会遇到这种情况,需要把一个对象的值赋值到另一个新对象,而且以后对新对象属性的修改不会影响到原对象,即两个对象是相互独立的,比如:
public clalss A{
private Long id;
private String name;
get set略......
public A(){}
public A(Long id,String name){
this.id = id;

this.name = name;
}
}
A a = new A(1,"a");
A b = null;
如果现在需要把对象a的内容全部复制到对象b中去,怎么办?如果你这样写,b = a;那就大错特错了,因为这样根据没有创建新对象,两个都是指向内存中同一个地址。或许你又会这样,b = new A(); 然后b.setId();
b.setName();这样一个一个的赋值。这样是创建了两个独立对象,但是还是有问题,如果对象属性有N多个怎么办,理论上这种情况是存在的,如果还是那样做,岂不是很累?怎么办?运用原型模式呗。实现原型模式很简单,只要待复制对象实现Cloneable接口,并重写父类Object的clone()方法即可。下面是我写的一个示例:
package com.prototype;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OptionalDataException;
import java.io.Serializable;


public abstract class Spoon implements Cloneable,Serializable {

private String name;

private double price;

private People people;

public People getPeople() {
return people;
}

public void setPeople(People people) {
this.people = people;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public double getPrice() {
return price;
}

public void setPrice(double price) {
this.price = price;
}

public Spoon() {
}

public Spoon(String name, double price) {
this.name = name;
this.price = price;
}

public Spoon(String name, double price,People people) {
this.name = name;
this.price = price;
this.people = people;
}

@Override

protected Object clone() {
Object object = null;
try {
object = super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException("Spoon is not Cloneable!");
}
return object;
}


protected Object deepClone() {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
Object object = null;
try {
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(this);
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi = new ObjectInputStream(bi);
object = oi.readObject();
} catch (OptionalDataException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return object;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
long temp;
temp = Double.doubleToLongBits(price);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Spoon other = (Spoon) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (Double.doubleToLongBits(price) != Double.doubleToLongBits(other.price))
return false;
return true;
}
}

package com.prototype;

public class SoupSpoon extends Spoon {
public SoupSpoon() {
super();
}

public SoupSpoon(String name,double price){
super(name,price);
}

public SoupSpoon(String name,double price,People people){
super(name,price,people);
}
}

package com.prototype;

import java.io.Serializable;


public class People implements Serializable{
private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public People(){}

public People(String name){
this.name = name;
}
}

package com.prototype;

public class Test {
public static void main(String[] args) {

//通过Cloneable接口浅复制一个新对象(注意Cloneable接口对于引用类型对象只能复制内存地址引用,即"浅复制")
Spoon spoon1 = new SoupSpoon("汤匙",20.5);
Spoon spoon2 = (SoupSpoon)spoon1.clone();

System.out.println("spoon1与spoon2相等吗?" + (spoon1.equals(spoon2)));
System.out.println("spoon1与spoon2是同一个对象吗?" + (spoon1 == spoon2));

System.out.println("");

//直接通过new关键字创建一个新对象
Spoon spoon3 = new SoupSpoon("汤匙",20.5);
Spoon spoon4 = new SoupSpoon("汤匙",20.5);

System.out.println("spoon3与spoon4相等吗?" + (spoon3.equals(spoon4)));
System.out.println("spoon3与spoon4是同一个对象吗?" + (spoon3 == spoon4));


System.out.println("");


//通过deepClone()深复制对象
Spoon spoon5 = new SoupSpoon("汤匙",20.5,new People("zhangsan"));
Spoon spoon6 = (SoupSpoon)spoon5.deepClone();
System.out.println("spoon5与spoon6相等吗?" + (spoon5.equals(spoon6)));
System.out.println("spoon5与spoon6是同一个对象吗?" + (spoon5 == spoon6));
System.out.println("spoon5与spoon6的people是同一个对象吗?" + (spoon5.getPeople() == spoon6.getPeople()));

}
}

其他不想多说,代码里已经表达的很清楚,唯一需要说明的是,Java对象复制分浅复制和深复制,浅复制指的是只复制非引用类型对象,深复制指的是如果类与类之间存在聚合依赖关系,那些被关联的对象也会被复制。每一个需要复制的对象都需要实现Clonable接口(它只是一个标识性接口,没有任何方法)并重写Object的clone()方法,如果一个类A关联类B,类B又关联类C.....理论上这种关系可能存在N层嵌套,如果还是每个类都这样处理,那麻烦就大了,怎么办?这时,我建议还是使用序列化的方式来实现对象深度复制比较好,首先用序列化方式实现代码才几行,非常简洁,再个就是可以用递归方式实现里,至于如何实现,下面会贴相关代码。
下面就要考虑重用性了,于是需要考虑写个工具类,来专门用于解决Java对象复制问题,下面是java对象克隆工具类的具体代码:
package com.prototype;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OptionalDataException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;


public class ClonUtils {

static Class[] needlessCloneClasses = new Class[]{String.class,Boolean.class,Character.class,Byte.class,Short.class,
Integer.class,Long.class,Float.class,Double.class,Void.class,Object.class,Class.class
};

private static boolean isNeedlessClone(Class c){
if(c.isPrimitive()){//基本类型
return true;
}
for(Class tmp:needlessCloneClasses){//是否在无需复制类型数组里
if(c.equals(tmp)){
return true;
}
}
return false;
}


private static Object createObject(Object value) throws IllegalAccessException{
try {
return value.getClass().newInstance();
} catch (InstantiationException e) {
return null;
} catch (IllegalAccessException e) {
throw e;
}
}


public static Object clone(Object value,int level) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException{
if(null == value){
return null;
}
if(level==0){
return value;
}
Class c = value.getClass();
if(isNeedlessClone(c)){
return value;
}
level--;
if(value instanceof Collection){//复制新的集合
Collection tmp = (Collection)c.newInstance();
for(Object v:(Collection)value){
tmp.add(clone(v,level));//深度复制
}
value = tmp;
}
else if(c.isArray()){//复制新的Array
//首先判断是否为基本数据类型
if(c.equals(int[].class)){
int[] old = (int[])value;
value = (int[])Arrays.copyOf(old, old.length);
}
else if(c.equals(short[].class)){
short[] old = (short[])value;
value = (short[])Arrays.copyOf(old, old.length);
}
else if(c.equals(char[].class)){
char[] old = (char[])value;
value = (char[])Arrays.copyOf(old, old.length);
}
else if(c.equals(float[].class)){
float[] old = (float[])value;
value = (float[])Arrays.copyOf(old, old.length);
}
else if(c.equals(double[].class)){
double[] old = (double[])value;
value = (double[])Arrays.copyOf(old, old.length);
}
else if(c.equals(long[].class)){
long[] old = (long[])value;
value = (long[])Arrays.copyOf(old, old.length);
}
else if(c.equals(boolean[].class)){
boolean[] old = (boolean[])value;
value = (boolean[])Arrays.copyOf(old, old.length);
}
else if(c.equals(byte[].class)){
byte[] old = (byte[])value;
value = (byte[])Arrays.copyOf(old, old.length);
}
else {
Object[] old = (Object[])value;
Object[] tmp = (Object[])Arrays.copyOf(old, old.length, old.getClass());
for(int i = 0;i<old.length;i++){
tmp[i] = clone(old[i],level);
}
value = tmp;
}
}
else if(value instanceof Map){//复制新的MAP
Map tmp = (Map)c.newInstance();
Map org = (Map)value;
for(Object key:org.keySet()){
tmp.put(key, clone(org.get(key),level));//深度复制
}
value = tmp;
}
else {
Object tmp = createObject(value);
if(tmp==null){//无法创建新实例则返回对象本身,没有克隆
return value;
}
Set<Field> fields = new HashSet<Field>();
while(c!=null&&!c.equals(Object.class)){
fields.addAll(Arrays.asList(c.getDeclaredFields()));
c = c.getSuperclass();
}
for(Field field:fields){
if(!Modifier.isFinal(field.getModifiers())){//仅复制非final字段
field.setAccessible(true);
field.set(tmp, clone(field.get(value),level));//深度复制
}
}
value = tmp;
}
return value;
}


public static Object clone(Object value) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException{
return clone(value,1);
}


public static Object deepClone(Object value) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException{
return clone(value,-1);
}


public static Object deepClone2(Object obj){
if(null == obj){
return null;
}
ByteArrayOutputStream bo = new ByteArrayOutputStream();
Object object = null;
try {
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(obj);
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi = new ObjectInputStream(bi);
object = oi.readObject();
} catch (OptionalDataException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return object;
}
}
刚才说了,建议用序列化方式,还有一个重要的原因是,递归方式里用到了JDK util包里Arrays工具类里的copyOf方法,而该方法是JDK 1.6以上版本才有的,再个Arrays.copyOf内部实现其实也是调用System.arraycopy()方法来辅助实现的,查看System.arraycopy()方法的源代码,你会发现它被native关键字修饰,被native修饰即表名该方法是一个本地方法,那何为本地方法?也就是说该方法通过JNI技术调用了当前操作系统的DLL文件,这样你的程序就丧失了跨平台性,综合以上考虑,所以我建议采用序列化方式。

原文:java教程:再谈Java设计模式关于原型模式(Prototype)http://www.52ij.com/jishu/104.html

(责任编辑:豆豆)
下一篇:

C++实现UrlEncode和UrlDecode

上一篇:

Ajax 实现静态刷新页面 带加载旋转图片

  • 信息二维码

    手机看新闻

  • 分享到
打赏
免责声明
• 
本文仅代表作者个人观点,本站未对其内容进行核实,请读者仅做参考,如若文中涉及有违公德、触犯法律的内容,一经发现,立即删除,作者需自行承担相应责任。涉及到版权或其他问题,请及时联系我们 xfptx@outlook.com