软件设计模式之原型模型(ProtoType Model)以及深复制和浅复制

欢迎各位大哥大姐访问个人博客码农峰酱

一、应用场景

  • 对同一个对象或者类似对象需要多次进行实例化时;
  • 对于实例化不方便而复制比较方便时。

二、原型模型定义

用一个已经创建的实例作为原型,通过复制该原型来创建一个和原型相同或者相似的新对象。在这里,原型对象指定了要创建的对象的种类,用这种方法创建对象非常有效,根本不需要知道创建对象的具体的细节。

三、原型模式中几个重要的角色:

(1)抽象原型类:规定了原型对象必须实现的接口;
(2)具体原型类:实现了抽象原型类的的clone()方法,是可以被复制的;
(3)访问类:使用具体类中的clone()方法来复制对象。

四、原型模式类图:

五、应用举例

应聘者对于不同的公司写不同的简历,但个人信息都相同,因此只需修改除个人信息之外的信息
常规做法是写一个简历类,根据不同的公司实现不同的简历对象,而原型模型:使用clone()方法,克隆多个不同的实例对象。使用原型模型,避免手动创建对象,不需要执行构造方法,减少工作量,提高性能。
1、浅复制

public class Resume implements Cloneable{/*实现Cloneable接口*/
    private String name;
    private String sex;
    private int age;
    private String company;
    private List<Experiment> experimentList;

    public List<Experiment> getExperimentList() {
        return experimentList;
    }

    public void addExperimentList(Experiment experiment) {
        this.experimentList .add(experiment);
    }

    public Resume(String name, String sex, int age, String company,List<Experiment> experimentList) {
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.company = company;
        this.experimentList  =experimentList;
    }
    public void setCompany(String company) {
        this.company = company;
    }

    public void Information(){
        System.out.println("个人信息:");
        System.out.println("Name:"+this.name+" Age:"+this.age+" Sex:"+this.age);
        System.out.println("目标公司:"+this.company);
        System.out.println("工作经历:");
        for (Experiment experiment:experimentList) {
            System.out.println("company:" + experiment.getCompanyName()+
                    " time:"+experiment.getTime()+"sallary:"+experiment.getSallary());
        }
    }
    /* *实现Cloneable接口的clone()方法 * 浅复制 * */
    public Object clone() throws CloneNotSupportedException{
        return  (Resume)super.clone();//调用父类clone()方法
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        List<Experiment> experimentList = new ArrayList<Experiment>();
        Experiment experiment1 = new Experiment("Tecent","2019.06-2022-7",20000);
        experimentList.add(experiment1);
        Resume resume = new Resume("yafeng","man",23,"HuaWei",experimentList);
        resume.Information();
        Resume resume1 = (Resume)resume.clone();
        resume1.setCompany("Alibaba");
        resume1.Information(); 
    }
}

上述代码的意思是当你第一次投递简历时你写了一份简历,所***司为华为;第二次再投阿里巴巴时,仅需修改目标公司的名称,其个人信息不变,这样做的好处就是省时省力,高效快捷。上述代码输出的结果如下:

个人信息:
Name:yafeng  Age:23  Sex:23
目标公司:HuaWei
工作经历:
company:Tecnet time:2019.06-2022-7sallary:20000.0
个人信息:
Name:yafeng  Age:23  Sex:23
目标公司:Alibaba
工作经历:
company:HuaWei time:2019.06-2022-7sallary:20000.0

那么到底什么是浅复制呢?在上述代码的基础上再添加如下代码,即向resume对象的experimentList属性中再添加一个数据,代码如下:

System.out.println("=======================================举例说明浅复制=====================================");
 Experiment experiment2 = new Experiment("Baidu","2022.08-2025-7",30000);
 resume.addExperimentList(experiment2);
 System.out.println(resume == resume1);
 System.out.println(resume.getExperimentList() == resume1.getExperimentList());

输出结果如下:

=======================================举例说明浅复制=====================================
个人信息:
Name:yafeng  Age:23  Sex:23
目标公司:Alibaba
工作经历:
company:Tecent time:2019.06-2022-7sallary:20000.0
company:Baidu time:2022.08-2025-7sallary:30000.0
false
true

resume == resume1为false,即resume 和resume1两个不同的对象,而resume.getExperimentList() == resume1.getExperimentList()为true说明在对象复制时仅仅复制了该对象属性的引用,而从上述输出中也可以看出,在给resume对象的experimentList属性添加一个数据时,resume1的experimentList属性也发生了变化,这就是浅复制。

浅复制总结成一句话就是:通过clone方法复制时,对象的属性通过复制引用的方式来完成对象复制的一种复制方式。

2、深复制(通过对象流实现)
将述代码中Resume和Experience两个类实现的接口换为Serializable,除测试代码其他的代码均不变,测试代码如下:

public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
    Resume resume=new Resume("yafeng","男",21);
    WorkExperimence workExperimence1= new WorkExperimence("Tencent","2015.07-2019.06",20000);
    resume.getWorkExperimenceList().add(workExperimence1);
    //将对象转换为字节写入流中
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oops = new ObjectOutputStream(baos);
    oops.writeObject(resume);
    //从流中读出
    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
    ObjectInputStream ois = new ObjectInputStream(bais);
    Resume resume1 = (Resume) ois.readObject();
    System.out.println("============================举例说明深复制=======================================");
    System.out.println(resume == resume1);
    System.out.println(resume.getWorkExperimenceList() == resume1.getWorkExperimenceList());
}
输出结果:
=========================举例说明深复制==================================
false
false

上述结果说明,深复制当中,复制后的对象和原对象是两个完全不同的对象,没有任何关联,只是它们的属性值都是相同的,后续对任何一个的修改或其他操作都不会对另外一个有影响!本文是通过对象流的读写来完成深复制的。

全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务