首先对原型模式进行一个简单概念说明:通过一个已经存在的对象,复制出更多的具有与此对象具有相同类型的新的对象。

在理解Java原型模式之前,首先需要理解Java中的一个概念:复制/克隆。

在博文《Java总结篇系列:java.lang.Object》一文中,对Java中的clone()方法进行了一定的阐述。同时,我们需要知道,Java中的对象复制/克隆分为浅复制和深复制。

一、浅复制:

我们知道,一个类的定义中包括属性和方法。属性用于表示对象的状态,方法用于表示对象所具有的行为。其中,属性既可以是Java中基本数据类型,也可以是引用类型。Java中的浅复制通常使用clone()方式完成。

当进浅复制时,clone函数返回的是一个引用,指向的是新的clone出来的对象,此对象与原对象分别占用不同的堆空间。同时,复制出来的对象具有与原对象一致的状态。

此处对象一致的状态是指:复制出的对象与原对象中的属性值完全相等==。

下面以复制一本书为例:

1.定义Book类和Author类:

 class Author {

     private String name;
private int age; 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;
} }
 class Book implements Cloneable {

     private String title;
private int pageNum;
private Author author; public Book clone() {
Book book = null;
try {
book = (Book) super.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return book;
} public String getTitle() {
return title;
} public void setTitle(String title) {
this.title = title;
} public int getPageNum() {
return pageNum;
} public void setPageNum(int pageNum) {
this.pageNum = pageNum;
} public Author getAuthor() {
return author;
} public void setAuthor(Author author) {
this.author = author;
} }

2.测试:

 package com.qqyumidi;

 public class PrototypeTest {

     public static void main(String[] args) {
Book book1 = new Book();
Author author = new Author();
author.setName("corn");
author.setAge(100);
book1.setAuthor(author);
book1.setTitle("好记性不如烂博客");
book1.setPageNum(230); Book book2 = book1.clone(); System.out.println(book1 == book2); // false
System.out.println(book1.getPageNum() == book2.getPageNum()); // true
System.out.println(book1.getTitle() == book2.getTitle()); // true
System.out.println(book1.getAuthor() == book2.getAuthor()); // true }
}

由输出的结果可以验证说到的结论。由此我们发现:虽然复制出来的对象重新在堆上开辟了内存空间,但是,对象中各属性确保持相等。对于基本数据类型很好理解,但对于引用数据类型来说,则意味着此引用类型的属性所指向的对象本身是相同的, 并没有重新开辟内存空间存储。换句话说,引用类型的属性所指向的对象并没有复制。

由此,我们将其称之为浅复制。当复制后的对象的引用类型的属性所指向的对象也重新得以复制,此时,称之为深复制。

 

二、深复制:

 Java中的深复制一般是通过对象的序列化和反序列化得以实现。序列化时,需要实现Serializable接口。

下面还是以Book为例,看下深复制的一般实现过程:

1.定义Book类和Author类(注意:不仅Book类需要实现Serializable接口,Author同样也需要实现Serializable接口!!):

 class Author implements Serializable{

     private String name;
private int age; 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;
} }
 class Book implements Serializable {

     private String title;
private int pageNum;
private Author author; public Book 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 (Book) ois.readObject();
} public String getTitle() {
return title;
} public void setTitle(String title) {
this.title = title;
} public int getPageNum() {
return pageNum;
} public void setPageNum(int pageNum) {
this.pageNum = pageNum;
} public Author getAuthor() {
return author;
} public void setAuthor(Author author) {
this.author = author;
} }

2.测试:

 public class PrototypeTest {

     public static void main(String[] args) throws ClassNotFoundException, IOException {
Book book1 = new Book();
Author author = new Author();
author.setName("corn");
author.setAge(100);
book1.setAuthor(author);
book1.setTitle("好记性不如烂博客");
book1.setPageNum(230); Book book2 = book1.deepClone(); System.out.println(book1 == book2); // false
System.out.println(book1.getPageNum() == book2.getPageNum()); // true
System.out.println(book1.getTitle() == book2.getTitle()); // false
System.out.println(book1.getAuthor() == book2.getAuthor()); // false }
}

从输出结果中可以看出,深复制不仅在堆内存上开辟了空间以存储复制出的对象,甚至连对象中的引用类型的属性所指向的对象也得以复制,重新开辟了堆空间存储。

至此:设计模式中的创建型模式总结完毕,一共有五种创建型模式,分别为:单例模式(SingleTon)、建造者模式(Builder)、工厂方法模式(Factory Method)、抽象工厂模式(Abstract Factory)和原型模式(Prototype)。每种模式适用于不同的场景,具体应用时需注意区分。

设计模式总结篇系列:原型模式(Prototype)的更多相关文章

  1. 设计模式(四)原型模式Prototype(创建型)

      设计模式(四)原型模式Prototype(创建型) 1.   概述 我们都知道,创建型模式一般是用来创建一个新的对象,然后我们使用这个对象完成一些对象的操作,我们通过原型模式可以快速的创建一个对象 ...

  2. 设计模式(五)原型模式 Prototype

    原型模式: 原型模式,是指基于一个已经给定的对象,通过拷贝的方式,创建一个新的对象,这个给定对象,就是“原型”. 在 Java 中,原型模式体现为 Object 的 clone() 方法. 所有类都可 ...

  3. 跟着实例学习设计模式(7)-原型模式prototype(创建型)

    原型模式是创建型模式. 设计意图:用原型实例指定创建对象的类型,并通过拷贝这个原型来创建新的对象. 我们使用构建简历的样例的类图来说明原型模式. 类图: 原型模式主要用于对象的复制.它的核心是就是类图 ...

  4. 设计模式系列之原型模式(Prototype Pattern)——对象的克隆

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  5. 小菜学习设计模式(四)—原型(Prototype)模式

    前言 设计模式目录: 小菜学习设计模式(一)—模板方法(Template)模式 小菜学习设计模式(二)—单例(Singleton)模式 小菜学习设计模式(三)—工厂方法(Factory Method) ...

  6. Java设计模式(4)原型模式(Prototype模式)

    Prototype模式定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是: ...

  7. Net设计模式实例之原型模式( Prototype Pattern)

    一.原型模式简介(Brief Introduction) 原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象. Specify the kin ...

  8. 乐在其中设计模式(C#) - 原型模式(Prototype Pattern)

    原文:乐在其中设计模式(C#) - 原型模式(Prototype Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 原型模式(Prototype Pattern) 作者:weba ...

  9. PHP设计模式 原型模式(Prototype)

    定义 和工厂模式类似,用来创建对象.但实现机制不同,原型模式是先创建一个对象,采用clone的方式进行新对象的创建. 场景 大对象的创建. 优点 1.可以在运行时刻增加和删除产品 2.可以改变值或结构 ...

  10. 设计模式(六)原型模式(Prototype Pattern)

    一.引言 在软件系统中,当创建一个类的实例的过程很昂贵或很复杂,并且我们需要创建多个这样类的实例时,如果我们用new操作符去创建这样的类实例,这未免会增加创建类的复杂度和耗费更多的内存空间,因为这样在 ...

随机推荐

  1. 编程菜鸟的日记-初学尝试编程-C++ Primer Plus 第6章编程练习8

    #include <iostream> #include <fstream> #include <cstdlib> const int SIZE=20; using ...

  2. spring ref &history&design philosophy

    Spring Framework Overview Spring是开发java application的通用框架,分为多个模块(modules),核心是core container,包括configu ...

  3. windows服务定时任务

    其实定时任务时不时会碰到,只不过解决方案也不是只有一个,网上也有很多文章,但是没有一篇说得很清楚,尤其是安装环节,今天就着重说一下安装, 其他步骤带过,C#开发windows服务,开发,安装,调试 1 ...

  4. Elasticsearch 滚动重启 必读

    关键词:elasticsearch , es , 滚动重启 , 禁止分片 由于之前es GC没有怎么调优,结果今天被大量scroll查询查挂了,GC 卡死了.然后为了先恢复给业务使用,也没什么其他办法 ...

  5. php基础-mysqli

    基本八个步骤 //连接数据库 $link = mysqli_connect('localhost', 'root', ''); //判断是否连接成功 if (!$link) { exit('数据库连接 ...

  6. Go语言基础之函数

    Go语言基础之函数 函数是组织好的.可重复使用的.用于执行指定任务的代码块.本文介绍了Go语言中函数的相关内容. 函数 Go语言中支持函数.匿名函数和闭包,并且函数在Go语言中属于“一等公民”. 函数 ...

  7. flink入门实例-Windows下本地模式跑SocketWordCount

    一般情况下,开发大数据处理程序,我们希望能够在本地编写代码并调试通过,能够在本地进行数据测试,然后在生产环境去跑“大”数据. 一.nc工具 配置windows的nc端口,在网上下载nc.exe(htt ...

  8. Super Jumping! Jumping! Jumping! ---HDU - 1087

    Nowadays, a kind of chess game called “Super Jumping! Jumping! Jumping!” is very popular in HDU. May ...

  9. Daily Pathtracer!安利下不错的Pathtracer学习资料

    0x00 前言 最近看到了我司大网红aras-p(Aras Pranckevičius)的博客开了一个很有趣的新系列<Daily Pathtracer~>,来实现一个简单的ToyPathT ...

  10. [Swift]LeetCode74. 搜索二维矩阵 | Search a 2D Matrix

    Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the follo ...