2020-07-19
发哥讲
发哥讲

其实上一节的末尾讲到如何去生成对象,其中有一个关于clone的,这其实就是Prototype原型模式. 通过克隆(拷贝)的方式生成对象

1、了解Prototype原型模式

引文:

在商品房销售系统中,房屋信息是基础信息。在系统运行前必须输入房屋的各种信息到系统中,这是一项枯燥的重复劳动。如果让用户重复输入房间的类型、面积和卫生间样式,这个系统肯定尚未运行就夭折了。实际上,一个小区楼盘的样式并不多,不同的只是楼号。另外,楼盘中的房间类型也非常有限,从而为解决输入问题提供了启示。所以我们可以事先创建一个楼盘模型,然后复制出更多的楼盘模型。复制后,只需要调整一下楼号等信息即可。原型模式也可以用来解决这类问题。

定义:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。

类型:创建类模式

类图:

原型模式是一种比较简单的模式,也非常容易理解,实现一个接口,重写一个方法即完成了原型模式。在实际应用中,原型模式很少单独出现。经常与其他模式混用,他的原型类Prototype也常用抽象类来替代。

Java中的实现方式:

1:implement Cloneable(此接口是clone()的声明,记住是规范就完事了)
2:重写Object的clone方法(涉及到浅拷贝和深拷贝)

注意:

深拷贝与浅拷贝问题中,会发生深拷贝的有java中的8中基本类型以及他们的封装类型,另外还有String类型。其余的都是浅拷贝。

2、浅拷贝

浅拷贝: 对值类型的成员变量进行值的复制,对引用类型的成员变量只复制引用,不复制引用的对象.

定义一只Sheep 羊

package cn.design.prototype;

import java.util.Date;

/**
* @author lin
* @version 1.0
* @date 2020/7/19 21:09
* @Description 羊
*/
public class Sheep implements Cloneable {
   String name;
   Date birthDay;    public Sheep(String name, Date birthDay) {
       this.name = name;
       this.birthDay = birthDay;
  }    @Override
   protected Object clone() throws CloneNotSupportedException {
       return super.clone();
  }    public String getName() {
       return name;
  }    public void setName(String name) {
       this.name = name;
  }    public Date getBirthDay() {
       return birthDay;
  }    public void setBirthDay(Date birthDay) {
       this.birthDay = birthDay;
  }
}

定义测试TestClone1

package cn.design.prototype;

import java.util.Date;

/**
* @author lin
* @version 1.0
* @date 2020/7/19 21:11
* @Description 浅克隆 测试类
*/
public class TestClone1 {
   public static void main(String[] args) throws CloneNotSupportedException {
       Date date = new Date(21312312312L);
       Sheep s1 = new Sheep("小利", date);
       System.out.println("s1 = " + s1);
       System.out.println("s1.getName() = " + s1.getName());
       System.out.println("s1.getBirthDay() = " + s1.getBirthDay());        System.out.println();        Sheep s2 = (Sheep) s1.clone();
       System.out.println("s2 = " + s2);
       System.out.println("s2.getName() = " + s2.getName());
       System.out.println("s2.getBirthDay() = " + s2.getBirthDay());        System.out.println();        // 拷贝完成之后 , 可以对 新对象进行修改
       s2.setName("多利");
       System.out.println("s2.getName() = " + s2.getName());
       // 对比s1
       System.out.println("s1.getName() = " + s1.getName());        System.out.println();        // 浅拷贝的问题 , 就是 内部 是引用的 date对象, 如果拷贝的新对象修改了 date对象, 则 源对象的date也被修改
       date.setTime(435345353453L);
       s2.setBirthDay(date);        System.out.println("s2.getBirthDay() = " + s2.getBirthDay());
       // 对比s1
       System.out.println("s1.getBirthDay() = " + s1.getBirthDay());   }
}

运行结果如下:

s1 = cn.design.prototype.Sheep@135fbaa4
s1.getName() = 小利
s1.getBirthDay() = Sat Sep 05 00:05:12 CST 1970 s2 = cn.design.prototype.Sheep@7ea987ac
s2.getName() = 小利
s2.getBirthDay() = Sat Sep 05 00:05:12 CST 1970 s2.getName() = 多利
s1.getName() = 小利 s2.getBirthDay() = Wed Oct 19 01:15:53 CST 1983
s1.getBirthDay() = Wed Oct 19 01:15:53 CST 1983

3、深拷贝

深拷贝: 对值类型的成员变量进行值的复制,对引用类型的成员变量也进行引用对象的复制.

浅拷贝的升级版,更注重全属性的拷贝。

定义Sheep2类

package cn.design.prototype;

import java.util.Date;

/**
* @author lin
* @version 1.0
* @date 2020/7/19 21:09
* @Description 羊2
*/
public class Sheep2 implements Cloneable {
   String name;
   Date birthDay;    public Sheep2(String name, Date birthDay) {
       this.name = name;
       this.birthDay = birthDay;
  }    @Override
   protected Object clone() throws CloneNotSupportedException {
       Date newDate = null;
       Sheep2 o = (Sheep2) super.clone();
       newDate = (Date) o.birthDay.clone();
       o.setBirthDay(newDate);
       return o;
  }    public String getName() {
       return name;
  }    public void setName(String name) {
       this.name = name;
  }    public Date getBirthDay() {
       return birthDay;
  }    public void setBirthDay(Date birthDay) {
       this.birthDay = birthDay;
  }
}

定义测试类TestClone2

package cn.design.prototype;

import java.util.Date;

/**
* @author lin
* @version 1.0
* @date 2020/7/19 21:11
* @Description 浅克隆 测试类
*/
public class TestClone2 {
   public static void main(String[] args) throws CloneNotSupportedException {
       Date date = new Date(21312312312L);
       Sheep2 s1 = new Sheep2("小利", date);
       System.out.println("s1 = " + s1);
       System.out.println("s1.getName() = " + s1.getName());
       System.out.println("s1.getBirthDay() = " + s1.getBirthDay());        System.out.println();        Sheep2 s2 = (Sheep2) s1.clone();
       System.out.println("s2 = " + s2);
       System.out.println("s2.getName() = " + s2.getName());
       System.out.println("s2.getBirthDay() = " + s2.getBirthDay());        System.out.println();        // 拷贝完成之后 , 可以对 新对象进行修改
       s2.setName("多利");
       System.out.println("s2.getName() = " + s2.getName());
       // 对比s1
       System.out.println("s1.getName() = " + s1.getName());        System.out.println();        // 对比浅拷贝, 测试 深拷贝
       date.setTime(435345353453L);
       s1.setBirthDay(date);        System.out.println("s2.getBirthDay() = " + s2.getBirthDay());
       // 对比s1
       System.out.println("s1.getBirthDay() = " + s1.getBirthDay());   }
}

运行结果如下:

s1 = cn.design.prototype.Sheep2@4ac68d3e
s1.getName() = 小利
s1.getBirthDay() = Sat Sep 05 00:05:12 CST 1970 Sat Sep 05 00:05:12 CST 1970
Sat Sep 05 00:05:12 CST 1970
s2 = cn.design.prototype.Sheep2@27082746
s2.getName() = 小利
s2.getBirthDay() = Sat Sep 05 00:05:12 CST 1970 s2.getName() = 多利
s1.getName() = 小利 s2.getBirthDay() = Sat Sep 05 00:05:12 CST 1970
s1.getBirthDay() = Wed Oct 19 01:15:53 CST 1983
与目标VM断开连接, 地址为: ''127.0.0.1:14378', transport: '套接字'', 传输: '{1}' Process finished with exit code 0

4、运用场景?

1、资源优化场景

类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。

2、性能和安全要求的场景:

通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。

3、一个对象多个修改者的场景

一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。

在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与Java融为浑然一体,大家可以随手拿来使用。

5、小结

1、Prototype模式用于隔离类对象的使用者和具体类型(易变类)的之间的耦合关系,但是这些易变类必须拥有稳定的接口.

2、Prototype模式对于"如何创建易变类的对象"采用"原型克隆"的方式来做,它使我们能非常灵活动态的创建某些拥有"稳定接口"的新对象.所需的工作仅仅是创建一个新类的对象即原型,然后在需要的地方不断的Clone.

3、Prototype模式的Clone方法可以利用Object自带的MemberwiseClone方法,注:该方法只能用于比较简单的类,只能实现浅拷贝,如果类中包含数组等引用类型,则需要使用序列化方法来实现类型的深拷贝

发哥讲

如果你觉得文章还不错,就请点击右上角选择发送给朋友或者转发到朋友圈~

● 扫码关注公众号, 转载请备注来源,和链接

7、Prototype 原型模式 通过复制创造实例 创造型模式的更多相关文章

  1. 8、Builder 建造者模式 组装复杂的实例 创造型模式

    1.什么是Builder模式 定义: 将一个复杂对象的构建与表示相分离,使得同样的构建过程可以创建不同的表示.大白话就是,你不需要知道这个类的内部是什么样的,只用把想使用的参数传进去就可以了,达到了解 ...

  2. [WCF编程]7.实例上下文模式

    一.实例上下文模式概述 实例上下文(IntanceContext Mode)表示服务端的服务实例与客户端的服务代理的绑定方式. 在实例化服务器对象时,WCF采用了3种不同的模式:单调(Per-Call ...

  3. C++设计模式-Prototype原型模式

    作用: 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. Prototype模式提供了一个通过已存在对象进行新对象创建的接口(Clone), Clone()实现和具体的语言相关,在C+ ...

  4. 设计模式(五):PROTOTYPE原型模式 -- 创建型模式

    1.定义 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 2.适用场景 原型模式的主要思想是基于现有的对象克隆一个新的对象出来,一般是有对象的内部提供克隆的方法,通过该方法返回一个对 ...

  5. js原生设计模式——7原型模式之真正的原型模式——对象复制封装

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  6. 设计模式(1)--Prototype(原型模式)--创建型

    1.模式定义: 原型模式就是用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象. 2.使用场景: 在原型模式中我们可以利用过一个原型对象来指明我们所要创建对象的类型,然后通过复制这个对象的 ...

  7. Java设计模式:Prototype(原型)模式

    概念定义 使用原型实例指定待创建对象的种类,并通过拷贝该原型来创建新的对象.Prototype模式允许一个原型对象克隆(复制)出多个与其相同的对象,而无需知道任何如何创建的细节. 应用场景 对象的创建 ...

  8. 一天一个设计模式——Prototype 原型模式

    一.模式说明 看了比较多的资料,对原型模式写的比较复杂,个人的理解就是模型复制,根据现有的类来直接创建新的类,而不是调用类的构造函数. 那为什么不直接调用new方法来创建类的实例呢,主要一个原因是如果 ...

  9. prototype原型模式中的问题

    对于每个构造函数来说,都有一个prototype属性.对于每个对象实例来说,都有_proto_属性. 参看下面代码: function Person(){} Person.prototype={ na ...

随机推荐

  1. day4 python 运算符

    python运算符 1.算数运算符( + - * / // % ** ) # + - * / // % ** # 加 减 乘 除 整除 余数 幂 ​ #注意 #1. / 得到浮点型, // 得看被除数 ...

  2. centos7.6静默安装oracle 11G RAC

    环境介绍, esxi6.0 ,VMware vSphere Client6.0 linux 版本Centos7.6(最小化安装) Oracle 版本 oracle 11g 11.2.0.4 虚拟化环境 ...

  3. JavaWeb基础(day15)( http + tomcat + servlet + 响应)

    HTTP+Tomcat+Servlet+响应 HTTP HTTP  超文本传输协议(Hyper Text  Transfer  Protocol  ),一种网络协议. 协议的组成和过程 HTTP协议由 ...

  4. 产品升级前后MD5码对比

    在做产品测试的时候,经常会需要对比升级前后的MD5码,这时可以通过终端登录设备,具体步骤如下: 1.在升级前时,将MD5码写入log1.info文件: check_md5 -d / -w log1.i ...

  5. 学习mysql,你必须要了解的 “ 索引 ” 基本知识

    1.select * 对效率的影响在我们平时的代码编写或面试题中,很多人都会疑惑:select * 到底合理吗? 如果说不合理,为什么?如果说合理,原因又是什么? 1).阿里规范 在阿里java规范中 ...

  6. 详解 CmProcess 跨进程通信的实现

    CmProcess 是 Android 一个跨进程通信框架,整体代码比较简单,总共 20 多个类,能够很好的便于我们去了解跨进程实现的原理. 个人猜测 CmProcess 也是借鉴了 VirtualA ...

  7. 谷歌浏览器扩展 crx 下载

    下方服务可让国内成功下载谷歌浏览器.crx 扩展,如谷歌浏览器无法安装,可以使用终极解决方法,把.crx 解压缩,然后在扩展中心中开启 开发者模式然后选择加载已解压的扩展程序. 需要注意的是解压缩的文 ...

  8. Maven原理学习

    文章目录 一.Maven概述 二.maven依赖管理 三.maven文件结构 四.maven仓库的种类以及彼此联系 五.maven标准目录结构 六.mvn命令 七.maven生命周期 八.maven的 ...

  9. java消除整型数组中重复的元素,排序后输出新数组

    法一: import java.util.Arrays; import java.util.Scanner; public class Main { public static void main(S ...

  10. 题解 洛谷 P5814 【[CTSC2001]终极情报网】

    读完题后不难看出本题是个网络流模型,源点流出的总流量为\(k\),源点向每个和总部直接联系的间谍连边,每个间谍向其能传递的间谍连容量为\(m\)的边,能与德军情报部进行联系的间谍向汇点连容量为\(in ...