原型模式

2019-08-02  本文已影响0人  闽越布衣

描述

    原型模式属于对象的创建模式。通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象。

简介

原型模式类图

    原型模式要求对象实现一个可以“克隆”自身的接口,这样就可以通过复制一个实例对象本身来创建一个新的实例。这样一来,通过原型实例创建新的对象,就不再需要关心这个实例本身的类型,只要实现了克隆自身的方法,就可以通过这个方法来获取新的对象,而无须再去通过new来创建。

角色

优缺点

优点

缺点

使用场景

克隆

克隆满足的条件

浅克隆和深克隆

示例

    为了更好的理解原型模式以及浅克隆与深克隆的区别,下面我们用西游记中孙悟空的分身术来做讲解。

浅克隆

public class GoldRingedStaff {
    private float height = 100.0f;
    private float diameter = 10.0f;

    /**
     * 增长行为,每次调用长度和半径增加一倍
     */
    public void grow() {
        this.diameter *= 2;
        this.height *= 2;
    }

    /**
     * 缩小行为,每次调用长度和半径减少一半
     */
    public void shrink() {
        this.diameter /= 2;
        this.height /= 2;
    }
}

public class Monkey implements Cloneable {
    private int height;
    private int weight;
    private Date birthDate;
    private GoldRingedStaff staff;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Monkey temp = null;
        try {
            temp = (Monkey) super.clone();
        } catch (CloneNotSupportedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            return temp;
        }
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public Date getBirthDate() {
        return birthDate;
    }

    public void setBirthDate(Date birthDate) {
        this.birthDate = birthDate;
    }

    public GoldRingedStaff getStaff() {
        return staff;
    }

    public void setStaff(GoldRingedStaff staff) {
        this.staff = staff;
    }

    @Override
    public String toString() {
        return "Monkey{" +
                "height=" + height +
                ", weight=" + weight +
                ", birthDate=" + birthDate +
                ", staff=" + staff +
                '}';
    }
}

public class Client {
    public static void main(String[] args) {
        Monkey monkey = new Monkey();
        monkey.setHeight(170);
        monkey.setWeight(100);
        monkey.setBirthDate(new Date());
        monkey.setStaff(new GoldRingedStaff());

        try {
            Monkey cloneMonkey = (Monkey) monkey.clone();
            System.out.println("大圣本尊的生日是:" + monkey.getBirthDate());
            System.out.println("克隆的大圣的生日是:" + monkey.getBirthDate());
            System.out.println("大圣本尊跟克隆的大圣是否为同一个对象 " + (monkey == cloneMonkey));
            System.out.println("大圣本尊持有的金箍棒跟克隆的大圣持有的金箍棒是否为同一个对象? " + (monkey.getStaff() == cloneMonkey.getStaff()));
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

程序输出结果:


浅克隆结果

    可以看出,首先,复制的大圣本尊具有和原始的大圣本尊对象一样的birthDate,而本尊对象不相等,这表明他们二者是克隆关系;其次,复制的大圣本尊所持有的金箍棒和原始的大圣本尊所持有的金箍棒为同一个对象。这表明二者所持有的金箍棒根本是一根,而不是两根。

深克隆

public class GoldRingedStaff implements Serializable{
    private float height = 100.0f;
    private float diameter = 10.0f;

    /**
     * 增长行为,每次调用长度和半径增加一倍
     */
    public void grow() {
        this.diameter *= 2;
        this.height *= 2;
    }

    /**
     * 缩小行为,每次调用长度和半径减少一半
     */
    public void shrink() {
        this.diameter /= 2;
        this.height /= 2;
    }
}

public class Monkey implements Cloneable, Serializable {
    private int height;
    private int weight;
    private Date birthDate;
    private GoldRingedStaff staff;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Monkey temp = null;
        try {
            temp = (Monkey) super.clone();
        } catch (CloneNotSupportedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            return temp;
        }
    }

    public Object deepClone() throws IOException, ClassNotFoundException {

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);

        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return ois.readObject();
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public Date getBirthDate() {
        return birthDate;
    }

    public void setBirthDate(Date birthDate) {
        this.birthDate = birthDate;
    }

    public GoldRingedStaff getStaff() {
        return staff;
    }

    public void setStaff(GoldRingedStaff staff) {
        this.staff = staff;
    }

    @Override
    public String toString() {
        return "Monkey{" +
                "height=" + height +
                ", weight=" + weight +
                ", birthDate=" + birthDate +
                ", staff=" + staff +
                '}';
    }
}

public class Client {
    public static void main(String[] args) {
        Monkey monkey = new Monkey();
        monkey.setHeight(170);
        monkey.setWeight(100);
        monkey.setBirthDate(new Date());
        monkey.setStaff(new GoldRingedStaff());

        try {
            Monkey cloneMonkey = (Monkey) monkey.deepClone();
            System.out.println("大圣本尊的生日是:" + monkey.getBirthDate());
            System.out.println("克隆的大圣的生日是:" + monkey.getBirthDate());
            System.out.println("大圣本尊跟克隆的大圣是否为同一个对象 " + (monkey == cloneMonkey));
            System.out.println("大圣本尊持有的金箍棒跟克隆的大圣持有的金箍棒是否为同一个对象? " + (monkey.getStaff() == cloneMonkey.getStaff()));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

程序输出结果:


深克隆结果

    从运行的结果可以看出,大圣的金箍棒和他的身外之身的金箍棒是不同的对象。这是因为使用了深克隆,从而把大圣本尊所引用的对象也都复制了一遍,其中也包括金箍棒。

上一篇下一篇

猜你喜欢

热点阅读