Java设计模式:Prototype(原型)模式
概念定义
使用原型实例指定待创建对象的种类,并通过拷贝该原型来创建新的对象。Prototype模式允许一个原型对象克隆(复制)出多个与其相同的对象,而无需知道任何如何创建的细节。
应用场景
- 对象的创建过程较为复杂且需要频繁创建
- 期望根据现有的实例来生成新的实例,例如:
- 对象种类繁多而无法整合到一个类时
- 难以通过指定类名生成实例时
- 希望解耦框架与生成的实例时
在实际应用中,Prototype模式很少单独出现。经常与其他模式混用。
原型实现
所有Java类都继承自java.lang.Object
,而Object类提供clone()方法来克隆对象。因此,Java类实现Cloneable接口并重写clone()方法后,即可实现Prototype模式。
实现Prototype模式的示例代码如下:
// 原型类(也可定义为interface Prototype extends Cloneable)
abstract class Prototype implements Cloneable {
private String name;
public void setName(String name) {this.name = name;}
public String getName() {return this.name;}
public abstract void doSomething();
@Override
public Object clone() { // clone()方法用public修饰
Object object = null;
try {
object = super.clone(); // 调用父类clone()方法
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return object;
}
}
// 具体实现类(继承自Prototype类自动具有克隆功能)
class ConcretePrototype extends Prototype{
public ConcretePrototype() { setName("ConcretePrototype"); }
@Override
public void doSomething() { System.out.println("I'll clone myself!"); }
}
public class PrototypeDemo {
public static void main(String[] args) {
ConcretePrototype cp = new ConcretePrototype();
cp.doSomething();
for(int i=0; i< 5; i++){
ConcretePrototype cloned = (ConcretePrototype)cp.clone();
System.out.println("I'm cloned by " + cloned.getName());
}
}
}
执行后输出如下:
I'll clone myself!
I'm cloned by ConcretePrototype
I'm cloned by ConcretePrototype
I'm cloned by ConcretePrototype
I'm cloned by ConcretePrototype
I'm cloned by ConcretePrototype
模式优缺点
Prototype模式的优点如下:
- 根据客户端要求实现运行时动态创建对象,客户端不需要知道对象的创建细节,便于代码的维护和扩展。
- 当对象的创建较为复杂或重复创建大量相似对象时,可简化对象创建,且性能比直接new对象更高(new会自动调用构造链中的所有构造方法,但clone不会调用任何类构造方法)。
- Prototype模式类似工厂模式,但没有工厂模式中的抽象工厂和具体工厂的层级关系,代码结构更清晰和简单。
缺点如下:
- 需要为每个类实现Cloneable接口并重写clone()方法,改造已有类时必须修改其源码,违背"开闭原则"。
- 单例模式与工厂模式、Prototype模式是冲突的,尽量不要混用。
- 在实现深拷贝(深克隆)时需要编写较为复杂的代码。
注意事项
clone()方法只拷贝对象中的基本数据类型,而不会拷贝数组、容器对象、引用对象等。若要实现深拷贝,必须将Prototype模式中的数组、容器对象、引用对象等另行拷贝。
例如,深拷贝一个对象时,该对象必须实现Cloneable接口并重写clone()方法,并在clone()方法内部将该对象引用的其他对象也克隆一份。同理,被引用的对象也要做同样的处理。
注意,Boolean、Byte、Character、Class、Double、Float、Integer、Long、Short、String以及大部分的Exception的子类均为不可变类,其对象没有必要实现深拷贝。此外,大部分的Java容器类都已实现克隆功能。
相较而言,clone()方法更适合数组深拷贝。但需要注意以下两点:
(1) 基本类型的一维数组可通过诸如(int[])data.clone()
的形式克隆,而基本类型的"二维数组"(实际上是类型诸如int[]的一维数组)需要按维克隆。例如:
public static int[][] twoDimensionArrayClone (int[][] tdArray){
int[][] copy = tdArray.clone();
for (int i = 0; i < tdArray.length; i++) {
copy[i] = tdArray[i].clone();
}
return copy;
}
(2) 当数组元素为普通Java对象时,克隆数组后还要克隆数组中包含的对象。以下示例详细展示了数组对象的不同浅拷贝和深拷贝方式:
class Person implements Cloneable {
public String name;
public Person(String name) {this.name = name;}
@Override
public Object clone() {
Object object = null;
try {
object = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return object;
}
}
public class ArrayPrototype {
public static void main(String[] args) {
Person[] origin = new Person[] { new Person("Mike"), new Person("Jack"), new Person("Jason") };
Person[] copyOf = Arrays.copyOf(origin, origin.length); // 浅拷贝(内部调用System.arraycopy,返回新数组)
Person[] arrayCopy = new Person[origin.length]; // 浅拷贝(可拷贝部分数组)
System.arraycopy(origin, 0, arrayCopy, 0, origin.length);
Person[] clonedCopy = origin.clone(); // 浅拷贝
System.out.println("origin=copyOf=arrayCopy=clonedCopy=" +
(origin[0] == copyOf[0] && copyOf[1] == arrayCopy[1] && arrayCopy[2] == clonedCopy[2]));
clonedCopy[0].name = "Lily";
System.out.println("Shallow Person[0]: " + origin[0].name + " -> " + clonedCopy[0].name);
Person[] deepCopy = new Person[origin.length]; // 深拷贝
for(int i = 0; i < origin.length; i++) { deepCopy[i] = (Person) origin[i].clone(); }
deepCopy[1].name = "Lily";
System.out.println("Deep Person[1]: " + origin[1].name + " -> " + clonedCopy[1].name);
Person[] deepCopy2 = Arrays.stream(origin).map(Person::clone).toArray(Person[]::new); // 深拷贝
deepCopy2[2].name = "Lucy";
System.out.println("Deep Person[2]: " + origin[2].name + " -> " + deepCopy2[2].name);
//origin=copyOf=arrayCopy=clonedCopy=true
//Shallow Person[0]: Lily -> Lily
//Deep Person[1]: Jack -> Jack
//Deep Person[2]: Jason -> Lucy
}
}
业界实践
- Action对象(Struts2)
- prototype创建的bean实例(Spring)
Java设计模式:Prototype(原型)模式的更多相关文章
- java设计模式4——原型模式
java设计模式4--原型模式 1.写在前面 本节内容与C++语言的复制构造函数.浅拷贝.深拷贝极为相似,因此建议学习者可以先了解C++的该部分的相关知识,或者学习完本节内容后,也去了解C++的相应内 ...
- JAVA 设计模式之原型模式
目录 JAVA 设计模式之原型模式 简介 Java实现 1.浅拷贝 2.深拷贝 优缺点说明 1.优点 2.缺点 JAVA 设计模式之原型模式 简介 原型模式是六种创建型设计模式之一,主要应用于创建相同 ...
- java设计模式之原型模式
原型模式概念 该模式的思想就是将一个对象作为原型,对其进行复制.克隆,产生一个和原对象类似的新对象.java中复制通过clone()实现的.clone中涉及深.浅复制.深.浅复制的概念如下: ⑴浅复制 ...
- 一天一个设计模式——Prototype 原型模式
一.模式说明 看了比较多的资料,对原型模式写的比较复杂,个人的理解就是模型复制,根据现有的类来直接创建新的类,而不是调用类的构造函数. 那为什么不直接调用new方法来创建类的实例呢,主要一个原因是如果 ...
- java设计模式之五原型模式(Prototype)
原型模式虽然是创建型的模式,但是与工程模式没有关系,从名字即可看出,该模式的思想就是将一个对象作为原型,对其进行复制.克隆,产生一个和原对象类似的新对象.本小结会通过对象的复制,进行讲解.在Java中 ...
- JAVA设计模式之 原型模式【Prototype Pattern】
一.概述: 使用原型实例指定创建对象的种类,而且通过拷贝这些原型创建新的对象. 简单的说就是对象的拷贝生成新的对象(对象的克隆),原型模式是一种对象创建型模式. 二.使用场景: 创建新的对象能够通过对 ...
- JAVA设计模式之原型模式(prototype)
原型模式: 原型模式又叫克隆模式 Java自带克隆模式 实现克隆模式必须实现Cloneable 接口,如果不实现会发生java.lang.CloneNotSupportedException异常 当某 ...
- 设计模式:Prototype 原型模式 - 同学你抄过别人的作业么?-clone()方法的使用
原型模式: 通过某个类的实例来创建对象 使用原型模式的好处: 好处是什么呢?当我们需要多次重复的创建一个类的示例的时候,我们可以使用new但是,new不仅仅耗费内存而且,如果new 某个类的构造方法中 ...
- 5.设计模式----prototype原型模式
原型模式:做到是原型,那肯定是自己本身才是原型,原型模式属于对象的创建模式. 关于原型模式的实现方式分2种: (1)简单形式.(2)登记形式,这两种表现形式仅仅是原型模式的不同实现. package ...
- JAVA 设计模式之 原型模式详解
原型模式(Prototype Pattern)是指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 原型模式利用的是克隆的原理,创建新的对象,JDK提供的Cloneable 和JSON. ...
随机推荐
- libnl概述
以下三个库都基于其核心库libnl: libnl-route:用于和Kernel中的Routing子系统交互. libnl-nf:用于和Kernel中的Netfilter子系统交互. libnl-ge ...
- Redis学习(一)简介
REmote DIctionary Server(Redis) 是一个由Salvatore Sanfilippo写的key-value存储系统. Redis是一个开源的使用ANSI C语言编写.遵守B ...
- echarts堆叠图计算总数和各部分
app.title = '堆叠条形图'; option = { tooltip : { trigger: 'axis', axisPointer : { // 坐标轴指示器,坐标轴触发有效 type ...
- 【第二章】Zabbix3.4监控SQLServer数据库和H3C交换机思科Cisco防火墙交换机教程笔记
监控SQLServer数据库 SSMS执行相关SQL SQL模板命名规则 Zabbix客户端导入模板 添加SQLServer监控图形 SQLServer服务器关联模板 监控思科Cisco防火墙交换机 ...
- Linux系统:centos7下搭建Nginx和FastDFS文件管理中间件
本文源码:GitHub·点这里 || GitEE·点这里 一.FastDFS简介 1.基础概念 FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储.文件同步.文件上传 ...
- Django之web框架原理
Web框架原理 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端. 这样我们就可以自己实现Web框架了. 先写一个 原始的web框架 imp ...
- HTML识别后台传输或者js变量中字符串里的 '\n' 并成功换行显示
HTML识别 string 里的 '\n' 并成功换行显示 设置标签的的css属性 white-space: pre-line; <div style='white-space: pre-lin ...
- iOS---------查看界面的流畅度
iOS查看屏幕帧数工具--YYFPSLabel iOS 保持界面流畅的技巧 iOS 优化界面流畅度的探讨 先研究一下 改天自己出一篇文章
- 43-安装 Docker Machine
前面我们的实验环境中只有一个 docker host,所有的容器都是运行在这一个 host 上的.但在真正的环境中会有多个 host,容器在这些 host 中启动.运行.停止和销毁,相关容器会通过网络 ...
- PHP删除数组中重复的元素
array_unique($arr): //删除重复元素 $arr = [1,2,3,0,1]; echo '<pre>'; var_dump($arr); $arr = array_un ...