原型模式(Prototype Pattern)也有人将原型模式称为克隆模式,是属于创造型设计模式,用于创建重复的对象,提供了一种创建对象的最佳方式。原型模式需要实现Cloneable接口,来实现对象的克隆。在实际的应用中,如果应用需要反复创建相同的对象时,并且创建这个对象需要花费大量时间或者需要访问权限,比如需要读取数据库,配置文件等,如果每次创建重复对象都需要读一次数据库,那么这种方式显然并不是高效的。这时可以考虑使用原型模式来解决,提高效率,此时只需要在创建原型对象时需要读取一次数据库或配置文件等,当后面需要需要创建这个对象时只需要从原型对象克隆一个出来即可。另外,原型模式也解决了构建复杂对象时繁琐的过程,原型模式不关心对象创建的细节,用户只需要调用克隆的方法就可以创建出一个一摸一样的对象,简化创建流程。

  既然原型模式也成为克隆模式,那么对象复制过程必然用到Java的克隆方法。所以你也需要了解什么是浅克隆和深克隆。

  浅克隆

  浅克隆复制的是对象基本类型的属性,对于引用类型的属性,浅克隆置复制该应用类型的地址,因为克隆对象的被克隆对象的应用类型属性是同一个内存地址,即为同一个对象,所以在修改其中一个对象的该属性时,另一个对象的改属性也会被修改,很容易将原型对象属性修改,这也是在使用原型模式时需要注意的地方。浅克隆在代码中的实现也比较简单,Java语言中本身就已经提供相关的接口和方法了,我们在使用时只需要继承Cloneable接口,重写clone方法即可实现对象的浅克隆。代码实现如下:

public class Sheep implements Cloneable {

    private String name;
private Color color = new Color(); public Sheep() {
} public Sheep(String name, String color) {
this.name = name; setColor(color);
} @Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
} @Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", color=" + color +
'}';
} public Color getColor() {
return color;
} public void setColor(String color) {
this.color.setColor(color);
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}

  

public class Color implements Cloneable {

    private String color;

    public Color() {
} public Color(String color) {
this.color = color;
} public String getColor() {
return color;
} public void setColor(String color) {
this.color = color;
} @Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
} @Override
public String toString() {
return "Color{" +
"color='" + color + '\'' +
'}';
}
}

  测试

public class Test {

    public static void main(String[] args) throws CloneNotSupportedException {
Sheep test = new Sheep("test","白色");
System.out.println(test);
Sheep clone = (Sheep) test.clone();
clone.setColor("黑色");
clone.setName("test01");
System.out.println(test);
System.out.println(clone);
} }

  运行程序时控制台打印出了:

  Sheep{name='test', color=Color{color='白色'}}

  Sheep{name='test', color=Color{color='黑色'}}

  Sheep{name='test01', color=Color{color='黑色'}}

  很显然,test对象创建时是白色的,然后用这个对象进行克隆得到 clone 实例,然后将clone 对象的颜色修改成黑色,name修改成test01,最终两个对象的颜色都变成了黑色,印证了上面说的话,对于引用类型克隆的是对象的内存地址。可能会有人好奇,String也是引用类型,为什么克隆对象修改了name属性,原型对象却没有被修改了?这是因为String是final类型,克隆过程中自然会是两个不同的内存地址。

  深克隆

  深克隆和浅克隆的区别在于,深克隆时引用类型属性复制的是该属性的值,与原型对象的拥有不同的内存地址,即两个是不同的对象,他们任意一个改属性值都不会影响到彼此。深克隆的实现方式有两种,第一种,实现Cloneable接口,重写clone方法,与浅克隆不同的是多一步将引用类型的变量再调用一次改变量的clone方法。不推荐用这种方法实现深克隆,每次修改对象的变量时都需要修改一次clone方法,违反了ocp原则。第二种,利用Java序列化与发序列化来实现,推荐使用这种方式。

  代码实现:

public class Color implements Cloneable, Serializable {

    private String color;

    public Color() {
} public Color(String color) {
this.color = color;
} public String getColor() {
return color;
} public void setColor(String color) {
this.color = color;
} @Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
} @Override
public String toString() {
return "Color{" +
"color='" + color + '\'' +
'}';
}
}

  

public class Sheep implements Cloneable, Serializable {

    private String name;
private Color color = new Color(); public Sheep() {
} public Sheep(String name, String color) {
this.name = name; setColor(color);
} /**
* 利用序列化与反序列化实现深克隆
* @return
*/
public Object deepClone() {
ByteArrayInputStream bis = null;
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
try {
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this); bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
return ois.readObject();
}catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (ois != null) {
ois.close();
}
if (bis != null) {
bis.close();
}
if (oos != null) {
oos.close();
}
if (bos != null) {
bos.close();
}
}catch (Exception e) {
e.printStackTrace();
}
}
return null;
} @Override
protected Object clone() throws CloneNotSupportedException {
Sheep clone = (Sheep) super.clone();
clone.color = (Color) clone.color.clone();
return clone;
} @Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", color=" + color +
'}';
} public Color getColor() {
return color;
} public void setColor(String color) {
this.color.setColor(color);
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}

  注意,如果使用Java的序列化与反序列化,则改对象需要实现Serializable接口,否则会抛序列化异常。

  

  总结

  1、原型模式有两种实现方式,第一种利用Object类中的clone方式,重写Cloneable的clone方法,浅克隆时直接调用Object类提供的clone方式即可。深克隆则需要再调用需要被克隆的对象的clone方法,当然该对象也必须实现Cloneable接口。第二种方式是利用Java的序列化和反序列化技术,这种方式也有一个缺点是所有需要序列化的变量都必须要实现Serializable接口。

  2、原型模式的优点:提高效率;屏蔽复杂的对象构建过程,简化代码。

  3、原型模式的缺点:

    1)配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。

    2)必须实现 Cloneable 接口或Serializable接口。

  4、原型模式的应用场景:

    1)资源优化场景。

    2)对象初始化需要大量的资源,包括数据,硬件资源等。

设计模式(Java语言)- 原型模式的更多相关文章

  1. java23种设计模式——四、原型模式

    源码在我的github和gitee中获取 目录 java23种设计模式-- 一.设计模式介绍 java23种设计模式-- 二.单例模式 java23种设计模式--三.工厂模式 java23种设计模式- ...

  2. Java设计模式5:原型模式

    原型模式 原型模式属于对象的创建模式,通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象,这就是原型模式的用意. 原型模式结构 原型模式要求对象实现一个 ...

  3. java 之 原型模式(大话设计模式)

    原型模式,在笔者理解看来就是克隆,当我们在创建第一个对象时,已经给对象赋值完毕,此时我们需要一个当前对象的副本,如果没有原型模式,我们会再次创建一个对象,然后后二次赋值,保证两个对象完全一致, 这样我 ...

  4. Java描述设计模式(05):原型模式

    本文源码:GitHub·点这里 || GitEE·点这里 一.原型模式简介 1.基础概念 原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出 ...

  5. 《JAVA设计模式》之原型模式(Prototype)

    在阎宏博士的<JAVA与模式>一书中开头是这样描述原型(Prototype)模式的: 原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办 ...

  6. 重学 Java 设计模式:实战原型模式

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 老板你加钱我的代码能飞 程序员这份工作里有两种人:一类是热爱喜欢的.一类是仅当成工作 ...

  7. 深度分析:java设计模式中的原型模式,看完就没有说不懂的

    前言 原型模式(Prototype模式)是指:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象 原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的 ...

  8. java常用设计模式三:原型模式

    在说原型模式之前先说一下浅拷贝和深拷贝的概念 一.浅拷贝和深拷贝 1.浅拷贝 在java中,对象创建后需要有一个引用变量来指向该对象实际的地址空间,也就是说引用变量与对象实体是两个不同的数据体.在Ob ...

  9. java设计模式-----5、原型模式

    原型(Prototype)模式是一种对象创建型模式,他采取复制原型对象的方法来创建对象的实例.使用原型模式创建的实例,具有与原型一样的数据. 原型模式的特点: 1.由原型对象自身创建目标对象.也就是说 ...

  10. 【java设计模式】-06原型模式

    原型模式简述 定义: 使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象 ,也就是通过复制现有对象实例产生新的对象,也就是所谓的"克隆" 实现方式: 1.实现Cl ...

随机推荐

  1. PHPStorm IDE 快捷键

    ⌘——Command ⌃ ——Control ⌥——Option/Alt ⇧——Shift ⇪——Caps Lock fn——功能键就是fn编辑 Command+alt+T 用 (if..else, ...

  2. Struts2-学习笔记系列(13)-类型转换异常和校验器

    Struts2框架有默认的类型转换错误拦截机制,该配置在struts-default.xml中,名叫conversionError,但是想使用需要继承ActionSupport. 默认的错误提示信息是 ...

  3. 关于Python 迭代器和生成器 装饰器

    Python 简介Python 是一个高层次的结合了解释性.编译性.互动性和面向对象的脚本语言. Python 的设计具有很强的可读性,相比其他语言经常使用英文关键字,其他语言的一些标点符号,它具有比 ...

  4. [编译] 7、在Linux下搭建安卓APP的开发烧写环境(makefile版-gradle版)—— 在Linux上用命令行+VIM开发安卓APP

    April 18, 2020 6:54 AM - BEAUTIFULZZZZ 目录 0 前言 1 gradle 安装配置 1.1 卸载系统默认装的gradle 1.2 下载对应版本的二进制文件 1.3 ...

  5. 运输层--------运输层与网络层的关系、UDP、TCP

    一.运输层与网络的区别: 网络层提供了主机之间的逻辑通信,而运输层为运行在不同主机上的进程之间提供了逻辑通信 二.实例证明: 考虑有两个家庭,一家位于美国东岸,一家位于美国西海岸,每家有12孩子.东海 ...

  6. sql 系统表协助集合

    一.判断字段是否存在: select * from syscolumns where id=object_id('表') and name='字段'

  7. 实验一 熟悉IDLE和在线编程平台

    实验目的 1.掌握python IDLE集成开发环境的安装与使用 2.熟悉在线编程平台 3.掌握基本的python程序编写.编译与运行程序的方法 实验内容 1.按照实验指导安装IDLE,尝试交互式运行 ...

  8. centos7 安装php7遇到的问题

    环境中安装过php 5.4,觉得版本太低了,因此删除旧版本安装了新版本 1. 安装epel-release 通过命令: rpm -ivh http://dl.fedoraproject.org/pub ...

  9. python调用小豆机器人实现自己的机器人!

    大家好,人工智能是不是很酷呢? 今天我们用python调用小豆机器人实现自己的机器人(可以结合往期的语音识别更酷哦) 好,废话不多说直接上代码 import requests i=input(&quo ...

  10. python成语接龙小游戏

    上一篇讲了小游戏的坑现在把源码放出来 #coding:utf-8 import string import pypinyin import sys import random print(" ...