设计模式三:原型模式

1 定义

用原型实例指定创建对象的种类,通过拷贝这些原型,创建新的对象

简单理解就是对象的克隆

2 使用clone方法实现

在java中可以使用Object对象中的clone方法来实现。
首先,如果想实现clone方法必须实现Cloneable接口,如下:

public class User implements Cloneable{
  private String username;
  private String password;

  public User(String username, String password) {
    this.username = username;
    this.password = password;
  }

  @Override
  protected Object clone() throws CloneNotSupportedException {
    return super.clone();
  }
}

这样看起来重写的clone方法什么都没做,为什么要实现一遍呢?因为在Object中,这个方法是protected的,意味着除了在子类的内部,以及同一个包下(Object所在的java.lang包),其他地方无法调用clone方法。关于protocted访问控制修饰符的具体作用范围,建议看这篇文章:Java 访问权限控制:你真的了解 protected 关键字吗?
注意,重写后的clone方法还是protected的,为了方便使用,可以将其提升为public,同时,返回可以改为User类型,可以看看协变返回类型,重写后如下:

public class User implements Cloneable{
  private String username;
  private String password;

  public User(String username, String password) {
    this.username = username;
    this.password = password;
  }

  @Override
  public User clone() throws CloneNotSupportedException {
    return (User) super.clone();
  }
}

但是,这种方式只是浅拷贝,如果User中有一个引用,这个引用并不会被拷贝,比如这样:

public class User implements Cloneable{
  private String username;
  private String password;
  private User friend;

  public User(String username, String password) {
    this.username = username;
    this.password = password;
  }

  @Override
  public User clone() throws CloneNotSupportedException {
    return (User) super.clone();
  }
   public User getFriend() {
    return friend;
  }

  public void setFriend(User friend) {
    this.friend = friend;
  }
}

拷贝后friend还是同一份引用。

public class Test {
  public static void main(String[] args) throws CloneNotSupportedException {
    User user = new User("leon", "123");
    user.setFriend(new User("friend", "123"));
    User clone1 = user.clone();
    System.out.println(clone1 == user);  // 返回false
    System.out.println(user.getFriend() == clone1.getFriend()); // 返回true
  }
}

如果要深拷贝,需要在clone方法中处理:

@Override
  public User clone() throws CloneNotSupportedException {
    User cloneUser = (User) super.clone();
    if (this.friend != null) {
      cloneUser.setFriend(this.friend.clone());
    }
    return cloneUser;
  }

2 使用对象序列化与反序列化实现

public User deepCopy() {
    User cloneUser = null;
    try {
      ByteArrayOutputStream bos = new ByteArrayOutputStream();
      ObjectOutputStream oos = new ObjectOutputStream(bos);
      oos.writeObject(this);

      ByteArrayInputStream bai = new ByteArrayInputStream(bos.toByteArray());
      ObjectInputStream ois = new ObjectInputStream(bai);
      cloneUser = (User) ois.readObject();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return cloneUser;
  }

总结

  • 创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能提高效率
  • 不用重新初始化对象,而是动态获得对象运行时的状态

你可能感兴趣的:(设计模式)