JAVA设计模式(05):创建型-原型模式(Prototype)-阿里云开发者社区

开发者社区> 明明如月> 正文

JAVA设计模式(05):创建型-原型模式(Prototype)

简介: 转自:http://blog.csdn.net/lovesomnus/article/details/23755505
+关注继续查看

张纪中版《西游记》以出乎意料的造型和雷人的台词遭到广大观众朋友的热议,我们在此对该话题不作过多讨论。但无论是哪个版本的《西游记》,孙悟空都是其中的一号雄性主角,关于他(或它)拔毛变小猴的故事几乎人人皆知,孙悟空可以用猴毛根据自己的形象,复制(又称“克隆”或“拷贝”)出很多跟自己长得一模一样的“身外身”来。在设计模式中也存在一个类似的模式,可以通过一个原型对象克隆出多个一模一样的对象,该模式称之为原型模式。


1 大同小异的工作周报 

Sunny软件公司一直使用自行开发的一套OA (Office Automatic,办公自动化)系统进行日常工作办理,但在使用过程中,越来越多的人对工作周报的创建和编写模块产生了抱怨。追其原因,Sunny软件公司的OA管理员发现,由于某些岗位每周工作存在重复性,工作周报内容都大同小异,如图1工作周报示意图。这些周报只有一些小地方存在差异,但是现行系统每周默认创建的周报都是空白报表,用户只能通过重新输入或不断复制粘贴来填写重复的周报内容,极大降低了工作效率,浪费宝贵的时间。如何快速创建相同或者相似的工作周报,成为Sunny公司OA开发人员面临的一个新问题。


工作周报示意义

20.gif

       Sunny公司的开发人员通过对问题进行仔细分析,决定按照如下思路对工作周报模块进行重新设计和实现:

       (1)除了允许用户创建新周报外,还允许用户将创建好的周报保存为模板;

       (2)用户在再次创建周报时,可以创建全新的周报,还可以选择合适的模板复制生成一份相同的周报,然后对新生成的周报根据实际情况进行修改,产生新的周报。

       只要按照如上两个步骤进行处理,工作周报的创建效率将得以大大提高。这个过程让我们想到平时经常进行的两个电脑基本操作:复制和粘贴,快捷键通常为Ctrl + C和Ctrl + V,通过对已有对象的复制和粘贴,我们可以创建大量的相同对象。如何在一个面向对象系统中实现对象的复制和粘贴呢?不用着急,本章我们介绍的原型模式正为解决此类问题而诞生。


2 原型模式概述

      在使用原型模式时,我们需要首先创建一个原型对象,再通过复制这个原型对象来创建更多同类型的对象。试想,如果连孙悟空的模样都不知道,怎么拔毛变小猴子呢?原型模式的定义如下:

原型模式(Prototype  Pattern):使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式是一种对象创建型模式。

      原型模式的工作原理很简单:将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝自己来实现创建过程。由于在软件系统中我们经常会遇到需要创建多个相同或者相似对象的情况,因此原型模式在真实开发中的使用频率还是非常高的。原型模式是一种“另类”的创建型模式,创建克隆对象的工厂就是原型类自身,工厂方法由克隆方法来实现。

      需要注意的是通过克隆方法所创建的对象是全新的对象,它们在内存中拥有新的地址,通常对克隆所产生的对象进行修改对原型对象不会造成任何影响,每一个克隆对象都是相互独立的。通过不同的方式修改可以得到一系列相似但不完全相同的对象。

       原型模式的结构如图2所示:

21.gif

     Sunny公司的开发人员通过对问题进行仔细分析,决定按照如下思路对工作周报模块进行重新设计和实现:

       (1)除了允许用户创建新周报外,还允许用户将创建好的周报保存为模板;

       (2)用户在再次创建周报时,可以创建全新的周报,还可以选择合适的模板复制生成一份相同的周报,然后对新生成的周报根据实际情况进行修改,产生新的周报。

       只要按照如上两个步骤进行处理,工作周报的创建效率将得以大大提高。这个过程让我们想到平时经常进行的两个电脑基本操作:复制和粘贴,快捷键通常为Ctrl + C和Ctrl + V,通过对已有对象的复制和粘贴,我们可以创建大量的相同对象。如何在一个面向对象系统中实现对象的复制和粘贴呢?不用着急,本章我们介绍的原型模式正为解决此类问题而诞生。


2 原型模式概述

      在使用原型模式时,我们需要首先创建一个原型对象,再通过复制这个原型对象来创建更多同类型的对象。试想,如果连孙悟空的模样都不知道,怎么拔毛变小猴子呢?原型模式的定义如下:

原型模式(Prototype  Pattern):使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式是一种对象创建型模式。

      原型模式的工作原理很简单:将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝自己来实现创建过程。由于在软件系统中我们经常会遇到需要创建多个相同或者相似对象的情况,因此原型模式在真实开发中的使用频率还是非常高的。原型模式是一种“另类”的创建型模式,创建克隆对象的工厂就是原型类自身,工厂方法由克隆方法来实现。

      需要注意的是通过克隆方法所创建的对象是全新的对象,它们在内存中拥有新的地址,通常对克隆所产生的对象进行修改对原型对象不会造成任何影响,每一个克隆对象都是相互独立的。通过不同的方式修改可以得到一系列相似但不完全相同的对象。

       原型模式的结构如图2所示:

22.gif

原型模式结构图

      在原型模式结构图中包含如下几个角色:

      ●Prototype(抽象原型类):它是声明克隆方法的接口,是所有具体原型类的公共父类,可以是抽象类也可以是接口,甚至还可以是具体实现类。

      ● ConcretePrototype(具体原型类):它实现在抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。

      ● Client(客户类):让一个原型对象克隆自身从而创建一个新的对象,在客户类中只需要直接实例化或通过工厂方法等方式创建一个原型对象,再通过调用该对象的克隆方法即可得到多个相同的对象。由于客户类针对抽象原型类Prototype编程,因此用户可以根据需要选择具体原型类,系统具有较好的可扩展性,增加或更换具体原型类都很方便。

      原型模式的核心在于如何实现克隆方法,下面将介绍两种在Java语言中常用的克隆实现方法:

1.通用实现方法

      通用的克隆实现方法是在具体原型类的克隆方法中实例化一个与自身类型相同的对象并将其返回,并将相关的参数传入新创建的对象中,保证它们的成员属性相同。示意代码如下所示:

1. class ConcretePrototype implements Prototype {
2. private String attr; // 成员属性
3. public void setAttr(String attr) {
4. this.attr = attr;
5.     }
6. public String getAttr() {
7. return this.attr;
8.     }
9. public Prototype clone(){
10. Prototype prototype = new ConcretePrototype(); // 创建新对象
11.         prototype.setAttr(this.attr);
12. return prototype;
13.     }
14. }


思考

能否将上述代码中的clone()方法写成:public Prototype clone() { return this; }?给出你的理由。

      在客户类中我们只需要创建一个ConcretePrototype对象作为原型对象,然后调用其clone()方法即可得到对应的克隆对象,如下代码所示:

1. Prototype obj1  = new ConcretePrototype();
2. obj1.setAttr("Sunny");
3. Prototype obj2  = obj1.clone();

      这种方法可作为原型模式的通用实现,它与编程语言特性无关,任何面向对象语言都可以使用这种形式来实现对原型的克隆。

2. Java语言提供的clone()方法

      学过Java语言的人都知道,所有的Java类都继承自java.lang.Object。事实上,Object类提供一个clone()方法,可以将一个Java对象复制一份。因此在Java中可以直接使用Object提供的clone()方法来实现对象的克隆,Java语言中的原型模式实现很简单。

      需要注意的是能够实现克隆的Java类必须实现一个标识接口Cloneable,表示这个Java类支持被复制。如果一个类没有实现这个接口但是调用了clone()方法,Java编译器将抛出一个CloneNotSupportedException异常。如下代码所示:

1. class ConcretePrototype implements  Cloneable{
2. ……
3. public Prototype  clone(){
4.       Object object = null;
5.       try {
6.          object = super.clone();
7.       } catch (CloneNotSupportedException exception) {
8.      System.err.println("Not support cloneable");
9.       }
10.       return (Prototype )object;
11.     }
12. ……
13. }


      在客户端创建原型对象和克隆对象也很简单,如下代码所示:

1. Prototype obj1  = new ConcretePrototype();
2. Prototype obj2  = obj1.clone();

      一般而言,Java语言中的clone()方法满足:

(1) 对任何对象x,都有x.clone() != x,即克隆对象与原型对象不是同一个对象;

(2) 对任何对象x,都有x.clone().getClass() == x.getClass(),即克隆对象与原型对象的类型一样;

(3) 如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。

      为了获取对象的一份拷贝,我们可以直接利用Object类的clone()方法,具体步骤如下:

(1) 在派生类中覆盖基类的clone()方法,并声明为public;

(2) 在派生类的clone()方法中,调用super.clone();

(3)派生类需实现Cloneable接口。

      此时,Object类相当于抽象原型类,所有实现了Cloneable接口的类相当于具体原型类。



版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
SQL Server 在多个数据库中创建同一个存储过程(Create Same Stored Procedure in All Databases)
原文:SQL Server 在多个数据库中创建同一个存储过程(Create Same Stored Procedure in All Databases) 一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 遇到的问题(Problems)...
1211 0
ArcGIS Pro体验02——启动、创建工程
所有的猜测都是眼睛看到的,自己想到的,可能不一定正确哈。 任务界面十分简洁,左上是创建新工程,右上是账户名称,左上是关于。 可以直接创建一个工程,Blank应该是无类型,最后保存再选择;Global Scene.aptx,应该与ArcGlobal相关;Local Scene.aptx,应该与Arc Scene相关;Map.aptx,应该与ArcMap相关。
845 0
PostgreSQL 12: 新增 pg_stat_progress_create_index 视图监控索引创建进度
PostgreSQL 12 版本之前,对PostgreSQL大表创建索引时是一个比较痛苦的过程,创建索引过程中无法得知索引创建进度,PostgreSQL 12 在运维监控功能方面得到增强,新增 pg_stat_progress_create_index 视图可以监控索引的创建进度,本文简单演示。
1341 0
JavaScript创建对象(三)——原型模式
在JavaScript创建对象(二)——构造函数模式中提到,构造函数模式存在相同功能的函数定义多次的问题。本篇文章就来讨论一下该问题的解决方案——原型模式。
1040 0
常见设计模式解析和实现(C++)Prototype模式(原型模式)
作用:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。 UML结构图:   抽象基类: 1)  Prototype:虚拟基类,所有原型的基类,提供Clone接口函数 接口函数: 1)  Prototype::Clone函数:纯虚函数,根据不同的派生类来实例化创建对象。
737 0
+关注
明明如月
阿里巴巴 资深Java开发工程师
342
文章
1
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载