大话设计模式之原型模式

参考—->程杰大神的《大话设计模式》—org
记一下一遍以后重复看时有新的理解,メモ
原型模式—>
原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.
总得来说,原型模式实际上就是从一个对象创建另一个新的对象,使新的对象有具有原对象的特征,期间创建细节无需知道。

Java 在java.lang中提供了一个interface Cloneable接口

UML 图–>
这里写图片描述

—>讲真一脸懵逼
通过需求去实现代码,再通过代码分析来理解这个模式。(双手摊,也只能这么安慰自己了。)
需求—>
通过一个建立的模板,能够打印出tom的自身的简历,然后Bob通过tom的建立去复制,得到后再加以修改变成自身的简历。
首先有一个工作的信息类

//工作的信息类
public class WorkExperience  {

    public String timeArea = null;//工作时间
    public String company = null;//工作的公司名称
}

然后是一个简历的模板—>

import java.util.ArrayList;

public class Resume implements Cloneable {

    private String name;//自身名字
    private String sex;//性别
    private int age;//年龄
    //家庭组成人员
    public ArrayList<String> famMem = new ArrayList<>();
    //自己的之前的工作经验
    public WorkExperience workExperience = null;

    //构造函数 新建这个建立模板的实例时传入利用这个简历模板的人的名字
    //并新建一个工作经验的实例
    public Resume(String name) {
        this.name = name;
        workExperience = new WorkExperience();
    }
    //供Bob复制Tom的简历时用于修改名字把自己的名字替换tom时调用
    public void setName(String name) {
        this.name = name;
    }
    //供调用这个模板的人书写自己的信息
    //供Bob复制Tom的简历时用于修改名字把自己的名字替换tom时调用
    public void setPersonal(String sex, int age, ArrayList<String> famMem) {
        this.age = age;
        this.sex = sex;
        this.famMem = famMem;
    }
    //供调用这个模板的人书写自己工作的信息
    //供Bob复制Tom的简历时用于修改工作调用
    public void setWork(String timeArea, String company) {
        workExperience.timeArea = timeArea;
        workExperience.company = company;
    }   
     //克隆方法 这个方法得详述
    public Resume clone() throws CloneNotSupportedException {
        return (Resume) super.clone();
    }
    //克隆方法 这个方法得详述
    public void display() {
        System.out.println(this.name + " " + this.sex + " " + this.age);
        System.out.print("Family member: ");
        for (String elem : famMem)
            System.out.print(elem + " ");
        System.out.println();
        System.out.print("Work experience: " + this.workExperience.timeArea);
        System.out.println(" " + this.workExperience.company);
    }// display
}

上述的UML图中的抽象类prototype类不常用(程神是这么说的,-_-)克隆又很常用 在Java中java.lang中提供了一個 interface Cloneable
官方中文API解释(-=-凑合着看)—>
public interface Cloneable
一个类实现 Cloneable接口的 Object.clone()方法表明,该方法对该类的实例字段复制使一场是合法的。
调用对象的克隆方法对一个不在例外CloneNotSupportedException被实施Cloneable界面结果实例。

按照惯例,实现此接口的类必须重写Object.clone(这是保护)与一个公共方法。看到在重写此方法的细节Object.clone()。

注意,这个接口是空不包含clone方法。因此,它是不可能的克隆一个对象仅仅凭借的事实,它实现了这个接口。即使克隆方法被调用时进行反思,也不能保证它会成功。

反正就是重写Object.clone() 再看看这个方法是干嘛的

官方中文API解释(-=-凑合着看)—>
类的方法Object clone执行特定的复制操作。首先,如果此对象的类不实现接口Cloneable,然后CloneNotSupportedException抛出。请注意,所有的数组都被实现的接口Cloneable,数组类型的clone T[]方法的返回类型是T[]其中T是任何参考或原始类型。否则,此方法创建此对象的类的新实例并初始化与正是这个对象的相应字段内容的各个领域,如分配;字段的内容不克隆自己。因此,该方法执行此对象的“浅复制”,而不是“深复制”操作。

反正看到最后一句话就是执行的浅复制而不是深复制。
啥事浅复制和深复制?

先看看源码的运行情况
客户端—->

import java.util.ArrayList;

public class client {

    public static void main(String[] args) throws CloneNotSupportedException {
        // TODO Auto-generated method stub
        //tom这个人用这个简历模板进行写自己的简历
        Resume resumeTom = new Resume("tom");
        ArrayList<String> famMem = new ArrayList<>();
        famMem.add("mother");
        famMem.add("father");
        resumeTom.setPersonal("man", 11, famMem);
        resumeTom.setWork("beijing", "baidu");
        //然后bob这个人没用模板类,直接去复制了tom的
        //然后修修改改成自己的简历
        Resume resumeBob = resumeTom.clone();
        resumeBob.setName("bob");
        famMem.add("sister");
        resumeBob.setPersonal("man", 22, famMem);
        resumeBob.setWork("shanghai", "alibaba");
        //打印两个人的简历
        resumeTom.display();
        resumeBob.display();
    }


}

打印结果--->
tom man 11
Family member: mother father sister 
Work experience: shanghai alibaba
bob man 22
Family member: mother father sister 
Work experience: shanghai alibaba

发现家庭成员和工作信息被bob改了之后tom的也被动修改和Bob的一样了。
这就有点清楚了
clone这个方法
如果字段是值类型的,则对该字段执行逐位复制,如果字段是引用类型,则复制引用但不赋值引用的对象因此,原始对象及其复本引用同一对象。
这也就是浅复制的概念。
也就是源码中的工作成员ArrayList famMem这个成员对象和工作信息对象workExperience 它们是复制了指向内存地址的引用,故而bob修改之后Tom和Bob引用了Bob修改之后的对象,变成了 指向了修改后的内存地址的引用。(应该可以这么理解,反正浅复制是不能复制对象,只能复制对象的引用。。。)
最后输出了修改之后的 信息。
解决方式就是用深复制—>也就是把引用对象的变量指向复制过的新的对象,而不是原有的被引用的对象。
说白了就是自己重写一下Object里的clone这个方法。

import java.util.ArrayList;

public class Resume implements Cloneable {

    private String name;
    private String sex;
    private int age;
    public ArrayList<String> famMem = new ArrayList<String>();
    public WorkExperience workExperience = null;

    public Resume(String name) {
        this.name = name;
        workExperience = new WorkExperience();
    }

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

    public void setPersonal(String sex, int age, ArrayList<String> famMem) {
        this.age = age;
        this.sex = sex;
        this.famMem = famMem;
    }

    public void setWork(String timeArea, String company) {
        this.workExperience.timeArea = timeArea;
        this.workExperience.company = company;
    }

    public Resume clone() throws CloneNotSupportedException {
        // return (Resume) super.clone();
        int age = this.age;
        String sex = this.sex;
        String name = new String(this.name);
        famMem = new ArrayList<String>(this.famMem);

        Resume rcopy = new Resume(name);
        rcopy.setPersonal(sex, age, famMem);
        rcopy.setWork(this.workExperience.timeArea, this.workExperience.company);
        return rcopy;

    }

    public void display() {
        System.out.println(this.name + " " + this.sex + " " + this.age);
        System.out.print("Family member: ");
        for (String elem : famMem)
            System.out.print(elem + " ");
        System.out.println();
        System.out.print("Work experience: " + this.workExperience.timeArea);
        System.out.println(" " + this.workExperience.company);
    } 
}

客户端不变
打印结果

tom man 11
Family member: mother father 
Work experience: beijing baidu
bob man 22
Family member: mother father sister 
Work experience: shanghai alibaba

其实该源码的ArrayList集合的本身就已经有了克隆的方法。
修改源码
重写简历类的克隆方法

import java.util.ArrayList;

public class Resume implements Cloneable {

    private String name;
    private String sex;
    private int age;
    public ArrayList<String> famMem = new ArrayList<String>();
    public WorkExperience workExperience = null;

    public Resume(String name) {
        this.name = name;
        workExperience = new WorkExperience();
    }

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

    public void setPersonal(String sex, int age, ArrayList<String> famMem) {
        this.age = age;
        this.sex = sex;
        this.famMem = famMem;
    }

    public void setWork(String timeArea, String company) {
        this.workExperience.timeArea = timeArea;
        this.workExperience.company = company;
    }

    public Resume clone() throws CloneNotSupportedException {
        // return (Resume) super.clone();
        int age = this.age;
        String sex = this.sex;
        String name = new String(this.name);
        //此处把这行代码注释掉 
        //若客户端类不变则无法实现对家庭成员对象的深复制
        //若用ArrayList集合的clone方法,修改客户端
**//    famMem = new ArrayList<String>(this.famMem);**

        Resume rcopy = new Resume(name);
        rcopy.setPersonal(sex, age, this.famMem);
        rcopy.setWork(this.workExperience.timeArea, this.workExperience.company);
        return rcopy;

    }

    public void display() {
        System.out.println(this.name + " " + this.sex + " " + this.age);
        System.out.print("Family member: ");
        for (String elem : famMem)
            System.out.print(elem + " ");
        System.out.println();
        System.out.print("Work experience: " + this.workExperience.timeArea);
        System.out.println(" " + this.workExperience.company);
    } 
}
import java.sql.Array;
import java.util.ArrayList;

public class client {

    public static void main(String[] args) throws CloneNotSupportedException {
        // TODO Auto-generated method stub

        // tom这个人用这个简历模板进行写自己的简历
        Resume resumeTom = new Resume("tom");
        ArrayList<String> famMemTom = new ArrayList<String>();
        famMemTom.add("mother");
        famMemTom.add("father");
        resumeTom.setPersonal("man", 11, famMemTom);
        resumeTom.setWork("beijing", "baidu");

        // 然后bob这个人没用模板类,直接去复制了tom的
        // 然后修修改改成自己的简历
        Resume resumeBob = resumeTom.clone();
        ArrayList<String> famMemBob = (ArrayList<String>) famMemTom.clone();
        resumeBob.setName("bob");
        famMemBob.add("sister");
        resumeBob.setPersonal("man", 22, famMemBob);
        resumeBob.setWork("shanghai", "alibaba");

        // 打印两个人的简历
        resumeTom.display();
        resumeBob.display();

    }

}

官方对ArrayList的解释—->

public Object clone()
返回该 ArrayList实例浅拷贝。(这些元素本身没有被复制。) 
重写: 
clone 方法重写,继承类  Object 
结果 
这 ArrayList实例克隆 

打印结果—>

tom man 11
Family member: mother father 
Work experience: beijing baidu
bob man 22
Family member: mother father sister 
Work experience: shanghai alibaba

猜你喜欢

转载自blog.csdn.net/qq_15623599/article/details/77573908