设计模式 – 原型模式(Prototype)

ü  原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象

ü  JAVA中可以通过实现Cloneable或者继承Cloneable类来实现对象的拷贝,然后就

可以调用clone()方法进行对象的复制了(直接调用会报CloneNotSupported

Exception)。但是此处需要注意的是clone()方法是由java.lang.Object类定义的,Object类是JAVA类层次的基类,因此所有类都会继承clone()方法,而不要误以为是Cloneabel接口(Cloneable)中有定义clone()方法;

ü  还需要注意的是clone()方法做的是浅拷贝,所做的操作是直接赋值字段的内容,即这个操作并不管字段对应的对象实例内容。假设现在有个字段对应到一个数组,当使用clone()方法进行复制时,复制的结果只对应到该数组的参照而已,并不会一个个复制该数组的元素。如果只做浅拷贝clone无法满足你的要求,设计类的程序员也可以重写clone()方法,自行定义想要的复制结果

ü  还需要注意的是:clone只会进行复制而已,并没有调用构造函数,如果该类在产生对象实例时需要做特殊的初始化,则应将处理操作语句放在clone方法之内;

实例:简历复制

Ø  文件:Resume.java

package com.yilong.prototype;

public class Resume implements Cloneable {

    private String name;

    private String sex;

    private int age;

    private String timearea;

    private String company;

    public Resume(String name) {

       this.name = name;

    }

    public void setPersonalInfo(String sex, int age) {

       this.sex = sex;

       this.age = age;

    }

    public void setWrokExperience(String timearea, String company) {

       this.timearea = timearea;

       this.company = company;

    }

    public Resume resumeClone() {

       Resume resume = null;

       try {

           resume = (Resume)clone();

       } catch (CloneNotSupportedException e) {

           e.printStackTrace();

       }

        return resume;

    }

    public void display() {

       System.out.println("---------------------------------");

       System.out.println("姓名:" + this.name);

       System.out.println("性别:" + this.sex + " 年龄:" + this.age);

       System.out.println("工作经历:" + this.timearea + " " + this.company);

       System.out.println("---------------------------------");

    }

}

Ø  测试文件Main.java

package com.yilong.prototype;

public class Main {

    public static void main(String[] args) {

       Resume resume1 = new Resume("逸龙");

       resume1.setPersonalInfo("", 22);

       resume1.setWrokExperience("2001-2004", "XX公司");

       Resume resume2 = resume1.resumeClone();

       resume2.setPersonalInfo("", 23);

       resume2.setWrokExperience("2001-2005", "XXX公司");

       resume1.display();

       resume2.display();

    }

}

打印结果:

---------------------------------

姓名:逸龙

性别:男 年龄:22

工作经历:2001-2004 XX公司

---------------------------------

---------------------------------

姓名:逸龙

性别:男 年龄:23

工作经历:2001-2005 XXX公司

---------------------------------

ü  浅复制:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象;当我们需要把复制的对象所引用的对象都复制一遍的时候,就需要用到深复制:把引用对象的变量指向复制过的新对象,而不是原来的被引用的对象;下面是浅复制可能带来的不满足需求的情况:

但结果显示为:

实例:将上述的工作经历单独设置为一个类

Ø  文件WorkInfo.java

package com.yilong.prototype;

public class WorkInfo {

    private String timeArea;

    private String company;

   

    public String getCompany() {

       return company;

    }

    public void setCompany(String company) {

       this.company = company;

    }

    public String getTimeArea() {

       return timeArea;

    }

    public void setTimeArea(String timeArea) {

       this.timeArea = timeArea;

    }

}

Ø  文件Resume.java

package com.yilong.prototype;

public class Resume implements Cloneable {

    private String name;

    private String sex;

    private int age;

    private WorkInfo workInfo;

    public Resume(String name) {

       this.name = name;

    }

    public void setPersonalInfo(String sex, int age) {

       this.sex = sex;

       this.age = age;

    }

    public Resume resumeClone() {

       Resume resume = null;

       try {

           resume = (Resume)clone();

       } catch (CloneNotSupportedException e) {

           e.printStackTrace();

       }

       return resume;

    }

    public void display() {

       System.out.println("---------------------------------");

       System.out.println("姓名:" + this.name);

       System.out.println("性别:" + this.sex + " 年龄:" + this.age);

       System.out.println("工作经历:" + this.workInfo.getTimeArea() + " " + this.workInfo.getCompany());

       System.out.println("---------------------------------");

    }

    public WorkInfo getWorkInfo() {

       return workInfo;

    }

    public void setWorkInfo(WorkInfo workInfo) {

       this.workInfo = workInfo;

    }

}

Ø  测试文件Main.java

package com.yilong.prototype;

public class Main {

    public static void main(String[] args) {

       Resume resume1 = new Resume("逸龙");

       resume1.setPersonalInfo("", 22);

       WorkInfo workInfo = new WorkInfo();

       workInfo.setTimeArea("2001-2003");

       workInfo.setCompany("XX公司");

       resume1.setWorkInfo(workInfo);

       Resume resume2 = resume1.resumeClone();

       resume2.setPersonalInfo("", 23);

       resume2.getWorkInfo().setTimeArea("2003-2004");

       resume2.getWorkInfo().setCompany("XXVV公司");

       resume1.display();

       resume2.display();

    }

}

打印结果:

---------------------------------

姓名:逸龙

性别:男 年龄:22

工作经历:2003-2004 XXVV公司

---------------------------------

---------------------------------

姓名:逸龙

性别:男 年龄:23

工作经历:2003-2004 XXVV公司

---------------------------------

结果说明:可见,打印的结果都是最后一次设置的工作经历的值,这主要是因为copy的是工作经历对象的引用,也就是说resume1resume2里的workInfo都是指向同一个WorkInfo对象,而要达到预期的目标,主要是了解其中的原理,即在修改WorkInfo对象的值前必须新new一个新的WorkInfo对象,然后将其值设置为原来的WorkInfo里的值,这样再修改就会修改新分配的那块WorkInfo内存的值,具体可以将文件Resume.java里的resumeClone()函数修改为:

public Resume resumeClone() {

       Resume resume = null;

       try {

           resume = (Resume)clone();

           WorkInfo workInfo = new WorkInfo();

           workInfo.setTimeArea(this.getWorkInfo().getTimeArea());

           workInfo.setCompany(this.getWorkInfo().getCompany());

           resume.setWorkInfo(workInfo);

       } catch (CloneNotSupportedException e) {

           e.printStackTrace();

       }

       return resume;

}

打印结果:

---------------------------------

姓名:逸龙

性别:男 年龄:22

工作经历:2001-2003 XX公司

---------------------------------

---------------------------------

姓名:逸龙

性别:男 年龄:23

工作经历:2003-2004 XXVV公司

---------------------------------

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值