文章内容
一、什么原型模式
原型模式,用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。
二、原型模式角色
- 抽象原型类:规定了具体原型对象必须实现的clone方法
- 具体原型类:实现抽象原型类的clone方法,它是可被复制的对象。
三、原型模式实现方式
- 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
- 深克隆:创建一个新对象,属性中引用的其它对象也会被克隆,不再指向原有对象地址。
四、原型模式优缺点
1、浅克隆
原型类需要实现JDK 的Cloneable接口的clone方法,客户端(调用者)只要调用clone方法即可复制一个新对象。
缺点:
对于原型类中的引用类型的成员属性被克隆后,仍指向原型对象的成员属性的地址,修改原型对象的属性值,将同时改变克隆对象对应的属性值。
2、深克隆
由于浅克隆存在的缺点,深克隆可以通过对象序列化后,再进行反序列化,就可以实现完全的克隆。原型类需要实现Serializable接口。
3、深克隆扩展
在实际工作中,深克隆场景还是比较多,但是实现深克隆主要借助于第三方工具包,性能和简便性都有保证,常见的如阿里巴巴的fastjson jar,原型类既不需要实现Cloneable接口,也不需要实现Serializable接口。
五、原型模式demo示例
1、浅克隆代码实现
public class Author {
//姓名
private String name;
//
private int age;
//住址
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Author{" +
"name='" + name + ''' +
", age=" + age +
", address='" + address + ''' +
'}';
}
}
public class Book implements Cloneable {
// 书名
private String name;
// 价格
private Double price;
// 出版日期
private String publishDate;
//作者
// 引用类型
private Author author;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public String getPublishDate() {
return publishDate;
}
public void setPublishDate(String publishDate) {
this.publishDate = publishDate;
}
public Author getAuthor() {
return author;
}
public void setAuthor(Author author) {
this.author = author;
}
/**
* 克隆方法,调用该方法将复制一个新对象并返回
* @return
* @throws CloneNotSupportedException
*/ @Override
public Book clone() throws CloneNotSupportedException {
return (Book) super.clone();
}
@Override
public String toString() {
return "Book{" +
"name='" + name + ''' +
", price=" + price +
", publishDate='" + publishDate + ''' +
", author=" + author +
'}';
}
}
public class CloneClient {
public static void main(String[] args) throws CloneNotSupportedException {
Author author = new Author();
author.setAddress("上海市青浦区");
author.setAge(20);
author.setName("胡大师");
Book book = new Book();
book.setAuthor(author);
book.setName("Python");
book.setPrice(88d);
book.setPublishDate("2020-01-12");
System.out.println("修改前,原型对象信息:"+book);
//克隆出的新对象
Book cloneBook = book.clone();
System.out.println("修改前,克隆对象信息:"+cloneBook);
System.out.println("原型对象和克隆对象的author引用同一个对象:"+(book.getAuthor() == cloneBook.getAuthor()));
System.out.println("===================================");
//修改原型对象的作者信息
author.setName("胡大帅");
author.setAge(30);
author.setAddress("上海市闵行区");
System.out.println("修改后,原型对象信息:"+book);
System.out.println("修改后,克隆对象信息:"+cloneBook);
System.out.println("原型对象和克隆对象的author引用同一个对象:"+(book.getAuthor() == cloneBook.getAuthor()));
}
}
控制台输出日志:
2、深克隆代码实现
public class Author implements Serializable {
//姓名
private String name;
//
private int age;
//住址
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Author{" +
"name='" + name + ''' +
", age=" + age +
", address='" + address + ''' +
'}';
}
}
public class Book implements Serializable {
// 书名
private String name;
// 价格
private Double price;
// 出版日期
private String publishDate;
//作者
// 引用类型
private Author author;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public String getPublishDate() {
return publishDate;
}
public void setPublishDate(String publishDate) {
this.publishDate = publishDate;
}
public Author getAuthor() {
return author;
}
public void setAuthor(Author author) {
this.author = author;
}
public Book clone(){
try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:/clone.txt"));) {
oos.writeObject(this);
oos.flush();
} catch (Exception e) {
e.printStackTrace();
}
try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/clone.txt"));) {
Book o = (Book)ois.readObject();
return o;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + ''' +
", price=" + price +
", publishDate='" + publishDate + ''' +
", author=" + author +
'}';
}
}
public class DeepCloneClient {
public static void main(String[] args) {
Author author = new Author();
author.setAddress("上海市青浦区");
author.setAge(20);
author.setName("胡大师");
Book book = new Book();
book.setAuthor(author);
book.setName("Python");
book.setPrice(88d);
book.setPublishDate("2020-01-12");
System.out.println("修改前,原型对象信息:"+book);
//克隆出的新对象
Book cloneBook = book.clone();
System.out.println("修改前,克隆对象信息:"+cloneBook);
System.out.println("原型对象和克隆对象的author指向不同地址:"+(book.getAuthor() == cloneBook.getAuthor()));
System.out.println("===================================");
//修改原型对象的作者信息
author.setName("胡大帅");
author.setAge(30);
author.setAddress("上海市闵行区");
System.out.println("修改后,原型对象信息:"+book);
System.out.println("修改后,克隆对象信息:"+cloneBook);
System.out.println("原型对象和克隆对象的author指向不同地址:"+(book.getAuthor() == cloneBook.getAuthor()));
}
}
控制台输出日志:
3、深克隆扩展代码实现
通过maven引入依赖包:
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
public class AliDeepCloneClient {
public static void main(String[] args) {
Author author = new Author("胡大帅",20,"上海");
Book book = new Book("Java编程",99d,"2020-01-12",author);
//使用JSON序列化为字符串
String str = JSON.toJSONString(book);
//再将字符串反序列化为对象
Book cloneBook = JSON.parseObject(str, Book.class);
System.out.println("修改前,原型对象信息="+book);
System.out.println("修改前,克隆对象信息="+cloneBook);
System.out.println("原型对象的author和克隆对象的author,指向地址="+(book.getAuthor() == cloneBook.getAuthor()));
//修改原型对象的author值
author.setAddress("黄浦区");
author.setAge(35);
System.out.println("修改后,原型对象信息="+book);
System.out.println("修改后,克隆对象信息="+cloneBook);
}
}
控制台输出日志: