在说原型模式之前,我想说说原型的概念。
什么是原型呢?我们都复印过文件吧,比如说我们只用一份文件,就可以复印出无数的复印件,这个原文件就是我们的原型。在Java语言中,原型对象就是我们要复制的对象,这里就涉及到了复制的概念。那原型模式就是根据现有实例生成新实例的模式。
一、原型模式概述
在《JAVA与模式》中这样描述原型模式:
原型模式属于对象的创建模式。通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象。
二、原型模式的类图
既然是一种设计模式,肯定是已经沉淀过的设计思想,因此有固定的方法套路让我们参考。原型模式的类图如下:
这里涉及到三个角色:
(1)Client角色:客户端类,也就是我们的调用者,提出创建对象的请求。
(2)抽象原型(Prototype)类/接口:这里可以是抽象类,也可以是接口类,此角色定义了具体的原型类需要实现的接口(复制接口)。
(3)具体的原型类(ConcretePrototype):具体的原型类,实现了抽象原型角色类或者接口定义的复制接口,用来实现复制现有实例来生成新实例的方法。
三、原型设计模式举例
实现复制,我们需要让Prototype接口类继承Cloneable接口类。
可能有人会认为Cloneable接口类中存在clone方法,其实没有。Cloneable接口类中没有定义任何方法,我们可以看下jdk中java.lang包下的Cloneable接口类:
根据注释我们可以明白,一个类实现<code> Cloneable </ code>接口,只是向 java.lang.Object#clone()方法表明它对于该方法来说是合法的。换句话说,它只是被用来标记“可以使用Object对象的clone()方法进行复制”。这样的接口也被称为“标记接口”(marker interface)。
那如果我们不继承Cloneable 接口,直接使用Object#clone()方法会怎样?注释也说了,会抛出java.lang.CloneNotSupportedException异常。大家不信可以尝试下,编译时就会报错。就算你用try-catch包裹,运行时还会抛出异常。
下面我们举一例说明,假设我们现在有一个需求,就是要实现将一个字符串放在一个特定符号(如*)包围的方框中显示,或者加上下划线显示出来。
这里,我们扩展一下原有的原型设计模式,增加一个管理类,实现类似于spring中的注册机制,用来管理所有注册的原型实例。
我们的类图如下:
1、定义原型接口类,里面包含两个方法,一个是复制方法,一个是实现将一个字符串放在一个特定符号(如*)包围的方框中显示,或者加上下划线显示出来的方法。
public interface Product extends Cloneable{ Product createClone(); void use(); }
2、定义具体的实现了原型接口类方法的类
①定义MessageBox类,实现特殊修饰符包裹的字符串展示
package com.zhaodf.pattern.prototypePattern; public class MessageBox implements Product { //定义字符串的展示修饰符 private char decochar; public MessageBox(char decochar) { this.decochar = decochar; } public Product createClone() { Product p = null; try { //这里调用Object的clone方法进行浅拷贝 p = (Product)clone(); }catch (CloneNotSupportedException e){ e.printStackTrace();; } return p; } public void use(String s) { int length = s.length(); for (int i=0;i<length+4;i++){ System.out.print(decochar); } System.out.println(); System.out.print(decochar+" "+s+" "+decochar); System.out.println(); for (int i=0;i<length+4;i++){ System.out.print(decochar); } } }
②定义UnderLinePen类,实现在字符串下展示下划线的效果
package com.zhaodf.pattern.prototypePattern; public class UnderLinePen implements Product { //定义字符串的展示修饰符 private char ulchar; public UnderLinePen(char ulchar) { this.ulchar = ulchar; } public Product createClone() { Product p = null; try { //这里调用Object的clone方法进行浅拷贝 p = (Product)clone(); }catch (CloneNotSupportedException e){ e.printStackTrace();; } return p; } public void use(String s) { int length = s.length(); System.out.println("\""+s+"\""); for (int i=0;i<length+4;i++){ System.out.print(ulchar); } System.out.println(); } }
3、定义一个管理类,专门用来管理注册的原型实例
package com.zhaodf.pattern.prototypePattern; import java.util.HashMap; import java.util.Map; public class Manager{ //将注册的实例放在map中 private Map<String,Product> showCase = new HashMap<String,Product>(); //将原型实例注册在map中 public void register(String name,Product proto){ showCase.put(name,proto); } //根据原型实例创建新的复制对象 public Product createProduct(String name){ Product product = showCase.get(name); return product.createClone(); } }
4、定义客户端调用类
package com.zhaodf.pattern.prototypePattern; public class Client { public static void main(String[] args){ Manager manager = new Manager(); UnderLinePen ulPen = new UnderLinePen('-'); MessageBox mb = new MessageBox('*'); manager.register("ulpen",ulPen); manager.register("msgBox",mb); Product p1 = manager.createProduct("ulpen"); p1.use("Hello,World"); Product p2 = manager.createProduct("msgBox"); p2.use("Hello,World"); } }
最后输出的效果为:
四、原型模式的好处
1、效率快:原型模式是利用了Object类的clone实现的对象复制,因此相比于直接使用new,它不需要重复属性初始化的步骤。另外,由于clone方法是一个native方法,因此,复制的效率比我们去new对象来的更快。
2、解耦:原型模式增加一个原型对象管理类,可以与原型对象类实现解耦,从而实现类组件复用。比如在示例中,我们在管理类中直接根据名称获取了原型对象。
五、答疑
关于clone方法的使用解释:
1、想要调用clone方法,必须要实现Cloneable接口(不论是原型对象实现了Cloneable接口还是其父类实现了Cloneable接口都可以)。在clone方法的源码检测了是否实现了Cloneable接口,否则抛出异常。
源码如下:
// Check if class of obj supports the Cloneable interface.
// All arrays are considered to be cloneable (See JLS 20.1.5)
if (!klass->is_cloneable()) {//这里检查了是否实现了Cloneable接口,如果没实现,会抛出异常CloneNotSupportException。
ResourceMark rm(THREAD);
THROW_MSG_0(vmSymbols::java_lang_CloneNotSupportedException(), klass->external_name());
}
2、clone方法的返回值是复制出的新的实例。clone方法内部所进行的处理是分配与被复制对象相同的内存空间,接着将要复制的实例中的字段的值复制到所分配的内存空间中去,这一点可以使用对象比较去判断,复制出的实例和原型对象的内存地址不是同一个。
源码如下:
// Make shallow object copy
const int size = obj->size();//取对象大小
oop new_obj = NULL;
if (obj->is_javaArray()) {//如果是数组
const int length = ((arrayOop)obj())->length();//取长度
new_obj = CollectedHeap::array_allocate(klass, size, length, CHECK_NULL);//分配内存,写入元数据信息
} else {
new_obj = CollectedHeap::obj_allocate(klass, size, CHECK_NULL);//分配内存,写入元数据信息
}
3、面试的时候常会问,在使用clone方法进行复制的时候,常会有的一行代码是什么?当然是super.clone()。
4、clone方法进行实例复制时,常会涉及到的就是浅拷贝和深拷贝的概念(也有叫浅克隆和深克隆的)。
①浅拷贝是指只克隆了原型对象中基本类型数据和对象内引用类型变量的地址引用,它内部的引用类型实例变量还是指向原先的堆内存区域。
②深拷贝不仅拷贝原型对象中的基本数据类型内容,而且拷贝原型对象包含的引用类型对象的内容。这一点我们在浅拷贝和深拷贝介绍中详细阐述。
相关推荐
Java 设计模式 - 原型模式详解 原型模式是 Java 设计模式之一,它用于创建对象时,指定创建对象的类型,并通过拷贝这些原型创建新的对象。该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原...
### Java设计模式详解 #### 创建型模式 **1.1 工厂方法(Factory Method)** 工厂方法模式定义了一个创建对象的接口,但允许子类决定实例化哪一个类。这使得一个类的实例化可以被推迟到其子类。这种模式在以下...
Java设计模式是软件开发中的一种最佳实践,它总结了在解决特定问题时程序员们经常采用的有效方法。这个“JAVA设计模式-chm版”资源显然包含了关于Java设计模式的详细信息,便于理解和应用。设计模式是对常见问题的...
Java设计模式详解合集是一份宝贵的资源,包含了丰富的面向对象设计原则和多种设计模式的深入讲解。这份资料旨在帮助开发者提升软件设计能力,遵循良好的编程实践,提高代码的可读性、可维护性和复用性。以下是其中...
在Java编程中,有23种经典的GoF(Gang of Four)设计模式,它们被分为三大类:创建型、结构型和行为型。本资源集合了这些模式的详细解释与源码分析,旨在帮助开发者深入理解和应用设计模式。 1. 创建型模式...
### Java设计模式详解 #### 一、概述 Java设计模式是一种在特定场景下解决软件设计问题的方法论。设计模式能够帮助开发者在面对复杂问题时,更有效地组织代码、提高程序的可维护性和可扩展性。根据不同的应用场景...
Java中的23种设计模式是软件工程中非常重要的概念,它们是解决常见编程问题的成熟解决方案,被广泛应用于各种复杂的软件系统中。这些模式在不同的上下文中提供了可重用的结构和行为,使得代码更加清晰、可维护和扩展...
### Java设计模式详解 #### 一、背景与概念 在软件工程领域,设计模式是一种用于解决常见问题的可重用解决方案。《Java设计模式PDF》是一本由James W. Cooper编写的经典书籍,该书详细介绍了Java编程语言中的设计...
内容包括统一建模语言基础知识、面向对象设计原则、设计模式概述、简单工厂模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式、单例模式、适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式、...
### Java设计模式的应用 #### 一、引言 在当今快速发展的软件开发领域,Java作为一门功能强大且灵活的语言,不仅拥有丰富的API资源,还能与强大的数据库系统无缝对接。这使得许多开发人员能够以模块化的形式构建...
" JAVA 设计模式概述" JAVA 设计模式是指在软件设计过程中,为了提高代码的可维护性、灵活性和可扩展性所使用的一些惯用解决方案。JAVA 设计模式可以分为三种:创建模式、结构模式和行为模式。 1. 创建模式 创建...
### Java设计模式详解 #### 1. 创建型模式 创建型模式主要关注的是对象的创建方式,它们提供了创建对象的最佳方法。以下是对几种常见的创建型模式的深入解析: ##### 1.1.1 工厂方法(Factory Method) **定义**...
Java设计模式详解 Java设计模式是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。 设计模式的六大原则...
《Java设计模式实战详解》 在Java编程领域,设计模式是一种通用、可重用的解决方案,用于解决在软件设计中常见的问题。这个压缩包“java-design-patterns-master”显然是一个专注于Java设计模式的学习资源,旨在...
设计模式是软件工程中的一种最佳实践,它是在特定上下文中解决常见问题的模板或蓝图。...在"java24种设计模式详解"这个资源中,你会找到每种模式的详细讲解和实例,这将有助于你深入理解并掌握它们。
Java 中 23 种设计模式详解 在软件设计中,设计模式是解决特定问题的通用解决方案。 Java 中有 23 种常见的设计模式,下面将对每种设计模式进行详细的解释: 1. 抽象工厂模式(Abstract Factory) 抽象工厂模式...
【Java原型模式详解】 原型模式(Prototype Pattern)是一种创建型设计...总之,原型模式在Java中是一种实用的设计模式,尤其适用于需要频繁创建相似对象的场合。通过合理运用,可以有效地提高代码的性能和可维护性。
### Java设计模式详解 在软件开发领域,设计模式是一种被广泛采用的解决方案,用来解决常见的设计问题。设计模式不仅能够帮助开发者写出可复用、可维护的代码,还能提高团队间的沟通效率。以下是对给定文件中提到的...
Java是一种广泛使用的面向对象的编程语言,而设计模式则是软件工程中解决常见问题的经验总结,是程序员在实践中形成的最佳实践。这份"根据《JAVA与设计模式》整理的笔记及示例代码"涵盖了Java语言和设计模式的核心...
### 设计模式——Java #### 1. 前言 设计模式是在软件工程领域内广泛应用的一种编程思想,它能够帮助开发者解决常见的设计问题,并提高软件的灵活性、可复用性和可维护性。《Java实用系统开发指南》一书中的作者...