bboyjing's blog

HeadFirst设计模式二十三【原型模式】

当创建给定类的实例的过程很昂贵或很复杂时,可以使用原型模式。原型模式的核心是复制,Java原生就是支持。因为所有的JavaBean都继承自Object,而Object类提供一个clone()方法,可以讲一个JavaBean对象复制一份。但是,这个JavaBean必须实现一个Cloneable接口,表明这个JavaBean支持复制。

场景描述

有一个场景可以很好地来理解这个模式,就是西游记里的孙悟空,拔毛一吹瞬间变出数百个一模一样的分身。或者火影忍者中鸣人地影分身也有异曲同工之妙。下面用孙悟空地例子来看下如何实现原型模式。

代码示例

  1. 创建金箍棒

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public class GoldRingedStaff implements Cloneable, Serializable {
    // 金箍棒高度
    private float height = 100.0F;
    // 金箍棒直径
    private float diameter = 10.0F;
    /**
    * 增长行为,每次调用长度和半径增加一倍
    */
    public void grow() {
    this.diameter *= 2.0;
    this.height *= 2;
    }
    /**
    * 缩小行为,每次调用长度和半径减少一半
    */
    public void shrink() {
    this.diameter /= 2;
    this.height /= 2;
    }
    }
  2. 创建Monkey类,也就是大圣本尊,因为它是一只猴子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    public class Monkey implements Cloneable, Serializable {
    private int height;
    private int weight;
    private GoldRingedStaff staff;
    private Date birthDate;
    public GoldRingedStaff getStaff() {
    return staff;
    }
    public Date getBirthDate() {
    return birthDate;
    }
    public Monkey() {
    this.staff = new GoldRingedStaff();
    this.birthDate = new Date();
    }
    /**
    * 浅克隆
    */
    @Override
    public Object clone() {
    Monkey temp = null;
    try {
    temp = (Monkey) super.clone();
    } catch (CloneNotSupportedException e) {
    System.out.println("Clone failed");
    }
    return temp;
    }
    /**
    * 深克隆
    */
    public Object deepClone() throws IOException, ClassNotFoundException {
    // 将对象写出到流中
    ByteArrayOutputStream bo = new ByteArrayOutputStream();
    ObjectOutputStream oo = new ObjectOutputStream(bo);
    oo.writeObject(this);
    // 然后将对象从流中读出来
    ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
    ObjectInputStream oi = new ObjectInputStream(bi);
    return oi.readObject();
    }
    }
  3. 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public class Test {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
    Monkey monkey = new Monkey();
    // 浅克隆大圣
    Monkey copyMonkey = (Monkey) monkey.clone();
    System.out.println("Monkey King's birth date = " + monkey.getBirthDate());
    System.out.println("Copy Monkey's birth date = " + copyMonkey.getBirthDate());
    System.out.println("Monkey King == Copy Monkey ? " + (monkey == copyMonkey));
    // 浅克隆的话,金箍棒指向的对象是同一个
    System.out.println("Monkey King's Staff == Copy Monkey's Staff ? " + (monkey.getStaff() == copyMonkey.getStaff()));
    System.out.println();
    // 深克隆大圣
    Monkey deepCopyMonkey = (Monkey) monkey.deepClone();
    System.out.println("Monkey King's birth date = " + monkey.getBirthDate());
    System.out.println("Copy Monkey's birth date = " + deepCopyMonkey.getBirthDate());
    System.out.println("Monkey King == Copy Monkey ? " + (monkey == deepCopyMonkey));
    // 深克隆,所有对象都不是同一个
    System.out.println("Monkey King's Staff == Copy Monkey's Staff ? " + (monkey.getStaff() == deepCopyMonkey.getStaff()));
    }
    }

这个模式其实就是用了Java原生的功能,需要注意的是,使用浅克隆还是深克隆对程序影响很大,需要我们在使用过程中去考虑。本章节就到这里了。