当前位置: 首页 > news >正文

设计模式总结篇系列:原型模式(Prototype)

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

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

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

一、浅复制:

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

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

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

下面以复制一本书为例:

1.定义Book类和Author类:

复制代码
 1 class Author {
 2 
 3     private String name;
 4     private int age;
 5 
 6     public String getName() {
 7         return name;
 8     }
 9 
10     public void setName(String name) {
11         this.name = name;
12     }
13 
14     public int getAge() {
15         return age;
16     }
17 
18     public void setAge(int age) {
19         this.age = age;
20     }
21 
22 }
复制代码
复制代码
 1 class Book implements Cloneable {
 2 
 3     private String title;
 4     private int pageNum;
 5     private Author author;
 6 
 7     public Book clone() {
 8         Book book = null;
 9         try {
10             book = (Book) super.clone();
11         } catch (CloneNotSupportedException e) {
12             // TODO Auto-generated catch block
13             e.printStackTrace();
14         }
15         return book;
16     }
17 
18     public String getTitle() {
19         return title;
20     }
21 
22     public void setTitle(String title) {
23         this.title = title;
24     }
25 
26     public int getPageNum() {
27         return pageNum;
28     }
29 
30     public void setPageNum(int pageNum) {
31         this.pageNum = pageNum;
32     }
33 
34     public Author getAuthor() {
35         return author;
36     }
37 
38     public void setAuthor(Author author) {
39         this.author = author;
40     }
41 
42 }
复制代码

2.测试:

复制代码
 1 package com.qqyumidi;
 2 
 3 public class PrototypeTest {
 4 
 5     public static void main(String[] args) {
 6         Book book1 = new Book();
 7         Author author = new Author();
 8         author.setName("corn");
 9         author.setAge(100);
10         book1.setAuthor(author);
11         book1.setTitle("好记性不如烂博客");
12         book1.setPageNum(230);
13 
14         Book book2 = book1.clone();
15         
16         System.out.println(book1 == book2);  // false
17         System.out.println(book1.getPageNum() == book2.getPageNum());   // true
18         System.out.println(book1.getTitle() == book2.getTitle());        // true
19         System.out.println(book1.getAuthor() == book2.getAuthor());        // true
20         
21     }
22 }
复制代码

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

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

 

 

二、深复制:

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

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

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

复制代码
 1 class Author implements Serializable{
 2 
 3     private String name;
 4     private int age;
 5 
 6     public String getName() {
 7         return name;
 8     }
 9 
10     public void setName(String name) {
11         this.name = name;
12     }
13 
14     public int getAge() {
15         return age;
16     }
17 
18     public void setAge(int age) {
19         this.age = age;
20     }
21 
22 }
复制代码
复制代码
 1 class Book implements Serializable {
 2 
 3     private String title;
 4     private int pageNum;
 5     private Author author;
 6 
 7     public Book deepClone() throws IOException, ClassNotFoundException{
 8         // 写入当前对象的二进制流 
 9         ByteArrayOutputStream bos = new ByteArrayOutputStream();  
10         ObjectOutputStream oos = new ObjectOutputStream(bos);  
11         oos.writeObject(this);
12         
13         // 读出二进制流产生的新对象  
14         ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());  
15         ObjectInputStream ois = new ObjectInputStream(bis);  
16         return (Book) ois.readObject();
17     }
18     
19     public String getTitle() {
20         return title;
21     }
22 
23     public void setTitle(String title) {
24         this.title = title;
25     }
26 
27     public int getPageNum() {
28         return pageNum;
29     }
30 
31     public void setPageNum(int pageNum) {
32         this.pageNum = pageNum;
33     }
34 
35     public Author getAuthor() {
36         return author;
37     }
38 
39     public void setAuthor(Author author) {
40         this.author = author;
41     }
42 
43 }
复制代码

2.测试:

复制代码
 1 public class PrototypeTest {
 2 
 3     public static void main(String[] args) throws ClassNotFoundException, IOException {
 4         Book book1 = new Book();
 5         Author author = new Author();
 6         author.setName("corn");
 7         author.setAge(100);
 8         book1.setAuthor(author);
 9         book1.setTitle("好记性不如烂博客");
10         book1.setPageNum(230);
11 
12         Book book2 = book1.deepClone();
13         
14         System.out.println(book1 == book2);  // false
15         System.out.println(book1.getPageNum() == book2.getPageNum());   // true
16         System.out.println(book1.getTitle() == book2.getTitle());        // false
17         System.out.println(book1.getAuthor() == book2.getAuthor());        // false
18         
19     }
20 }
复制代码

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

 

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

 

---------------------------------------------------------------------------------
笔者水平有限,若有错漏,欢迎指正,如果转载以及CV操作,请务必注明出处,谢谢!
分类: 设计模式

本文转自Windstep博客园博客,原文链接:http://www.cnblogs.com/lwbqqyumidi/p/3746821.html,如需转载请自行联系原作者

相关文章:

  • oracle开启/关闭archlog
  • java虚拟机所管理的内存包括的运行时数据区域
  • Chrome浏览器查看cookie
  • 生成树协议设置
  • Java 系列文章
  • .Net开发笔记(二十)创建一个需要授权的第三方组件
  • 2015年热门的国产开源软件TOP 50
  • java基础面试题
  • 智能手机:“单兵作战”已死,多元化营销永生
  • mac修复ab及siege安装
  • 7 -- Spring的基本用法 -- 12... Spring 3.0 提供的表达式语言(SpEL)
  • 每日阅读
  • win 下 apache 实现负载均衡
  • PHP下ajax跨域的解决方案之jsonp
  • nginx反向代理架构与安装配置(一)
  • Apache Pulsar 2.1 重磅发布
  • CentOS 7 防火墙操作
  • Gradle 5.0 正式版发布
  • JavaScript中的对象个人分享
  • Java多态
  • October CMS - 快速入门 9 Images And Galleries
  • PHP的类修饰符与访问修饰符
  • 代理模式
  • 关于Android中设置闹钟的相对比较完善的解决方案
  • 前端每日实战:61# 视频演示如何用纯 CSS 创作一只咖啡壶
  • 入手阿里云新服务器的部署NODE
  • 算法---两个栈实现一个队列
  • 王永庆:技术创新改变教育未来
  • 直播平台建设千万不要忘记流媒体服务器的存在 ...
  • ​决定德拉瓦州地区版图的关键历史事件
  • #DBA杂记1
  • $ is not function   和JQUERY 命名 冲突的解说 Jquer问题 (
  • (13):Silverlight 2 数据与通信之WebRequest
  • (delphi11最新学习资料) Object Pascal 学习笔记---第5章第5节(delphi中的指针)
  • (javascript)再说document.body.scrollTop的使用问题
  • (Redis使用系列) Springboot 使用redis实现接口幂等性拦截 十一
  • (力扣)循环队列的实现与详解(C语言)
  • (图)IntelliTrace Tools 跟踪云端程序
  • ***原理与防范
  • ... fatal error LINK1120:1个无法解析的外部命令 的解决办法
  • .360、.halo勒索病毒的最新威胁:如何恢复您的数据?
  • .bat批处理(一):@echo off
  • .NET MVC第五章、模型绑定获取表单数据
  • .Net mvc总结
  • .net 获取url的方法
  • .NET/C# 项目如何优雅地设置条件编译符号?
  • .NET的微型Web框架 Nancy
  • @GetMapping和@RequestMapping的区别
  • @开发者,一文搞懂什么是 C# 计时器!
  • [145] 二叉树的后序遍历 js
  • [Android] Upload package to device fails #2720
  • [AX]AX2012 SSRS报表Drill through action
  • [C/C++]数据结构----顺序表的实现(增删查改)
  • [c++] 单例模式 + cyberrt TimingWheel 单例分析
  • [C++参考]拷贝构造函数的参数必须是引用类型