再谈Java设计模式关于原型模式(Prototype)

<p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-size: 14px; widows: 2; line-height: 22px; font-family: Tahoma, 'Microsoft Yahei'; orphans: 2; color: rgb(68, 68, 68);">首先需要弄清楚什么叫原型模式,或者说为什么要有原型模式,运用它会给我们带来什么或能解决什么问题?原型模式(Prototype)同抽象工厂模式同属于创建型模式,它主要关注于大量相同或相似对象的创建问题,<a target=_blank href="http://www.52ij.com/app/" target="_blank" style="border: none; text-decoration: none; color: rgb(0, 136, 204);"><u>应用</u></a>原型模式就是先需要一个原对象,然后通过对原对象进行复制(克隆),来产生一个与原对象相同或相似的新对象。注意这里所说的对象相同不是指复制出来的副本对象与原对象是同一个对象,相反复制出来的副本对象必须和原对象是两个不同的对象,只是两个对象的内容相同。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-size: 14px; widows: 2; line-height: 22px; font-family: Tahoma, 'Microsoft Yahei'; orphans: 2; color: rgb(68, 68, 68);">     我们在编程过程中,经常会遇到这种情况,需要把一个对象的值赋值到另一个新对象,而且以后对新对象属性的修改不会影响到原对象,即两个对象是相互独立的,比如:</p><pre name="code" class="java">  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;
/**
 * 汤匙基类
 * 
 * @author Lanxiaowei
 * @createTime 2011-10-10 09:04
 */
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;
 }
 
 /**
  * 深度复制(推荐使用序列化的方式)
  * @return
  */
 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;
 }
    /**
     * 因为对于引用类型对象默认都是继承自Object类,
     * 而Object类的equals()默认实现就是比较两者的内存地址引用,
     * 所以需要重写equals()和hashCode()
     * 至于为什么重写equals()还要重写hashCode(),那是sun的推荐做法
     * (因为当对象作为散列key时用到key的hashCode,
     * 而sun又规定两个对象若equals()为true,则hashCode()返回结果也应该相等)
     */
 @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;
/**
 * 汤匙子类
 * @author Lanxiaowei
 * @createTime 2011-10-10 09:20
 */
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;
/**
 * 使用人
 * 
 * @author Lanxiaowei
 * @createTime 2011-10-10 11:19
 */
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;
/**
 * 测试类
 * 
 * @author Lanxiaowei
 * @createTime 2011-10-10 11:34
 */
public class Test {
 public static void main(String[] args) {
  /******************************************测试对象浅复制 begin************************************************/
  //通过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));
  /******************************************测试对象浅复制 end**************************************************/
  
  System.out.println("");
  
  /******************************************测试对象深复制 begin************************************************/
  //通过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()));
  /******************************************测试对象深复制 end**************************************************/
 }
}

其他不想多说,代码里已经表达的很清楚,唯一需要说明的是,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;  
/**
 * 克隆工具类
 * @author Lanxiaowei
 * @createTime 2011-10-10 12:51
 */
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  
    };   
    /**  
     * 判断该类型对象是否无需复制  
     * @param c 指定类型  
     * @return 如果不需要复制则返回真,否则返回假  
     */  
    private static boolean isNeedlessClone(Class c){   
        if(c.isPrimitive()){//基本类型   
            return true;   
        }   
        for(Class tmp:needlessCloneClasses){//是否在无需复制类型数组里   
            if(c.equals(tmp)){   
                return true;   
            }   
        }   
        return false;   
    }   
       
    /**  
     * 尝试创建新对象  
     * @param c 原始对象  
     * @return 新的对象  
     * @throws IllegalAccessException  
     */  
    private static Object createObject(Object value) throws IllegalAccessException{   
            try {   
                return value.getClass().newInstance();   
            } catch (InstantiationException e) {   
                return null;   
            } catch (IllegalAccessException e) {   
                throw e;   
            }   
    }   
       
    /**  
     * 复制对象数据  
     * @param value 原始对象  
     * @param level 复制深度。小于0为无限深度,即将深入到最基本类型和Object类级别的数据复制;  
     *                      大于0则按照其值复制到指定深度的数据,
     *                      等于0则直接返回对象本身而不进行任何复制行为。  
     * @return 返回复制后的对象  
     * @throws IllegalAccessException  
     * @throws InstantiationException  
     * @throws InvocationTargetException  
     * @throws NoSuchMethodException  
     */  
    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;   
    }   
       
    /**  
     * 浅表复制对象  
     * @param value 原始对象  
     * @return 复制后的对象,只复制一层  
     * @throws IllegalAccessException  
     * @throws InstantiationException  
     * @throws InvocationTargetException  
     * @throws NoSuchMethodException  
     */  
    public static Object clone(Object value) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException{   
        return clone(value,1);   
    }   
       
    /**  
     * 深度复制对象(通过Java反射+递归方式实现) 
     * @param value 原始对象  
     * @return 复制后的对象  
     * @throws IllegalAccessException  
     * @throws InstantiationException  
     * @throws InvocationTargetException  
     * @throws NoSuchMethodException  
     */  
    public static Object deepClone(Object value) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException{   
        return clone(value,-1);   
    }   
    
    /**
     * 深度复制对象(采用序列化方式实现,推荐使用这种方法)
     * @param obj 被复制对象
     * @return 复制后的副本对象
     */
    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文件,这样你的程序就丧失了跨平台性,综合以上考虑,所以建议采用序列化方式。
 

本文来源 我爱IT技术网 http://www.52ij.com/jishu/104.html 转载请保留链接。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值