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. 数据可视化之 图表篇(一)Power BI可视化,几张图表认识疫情现状

    ​近期国际疫情愈演愈烈,在这个特殊的时期,一方面仍要照顾好自己.不要为疫情防治添乱,另一方面,也可以利用疫情数据提升自己的数据分析和可视化技能. 下面是我制作的几个可视化图表,分别注释了每个可视化用到 ...

  2. 数据分析01 /numpy模块

    数据分析01 /数据分析之numpy模块 目录 数据分析01 /数据分析之numpy模块 1. numpy简介 2. numpy的创建 3. numpy的方法 4. numpy的常用属性 5. num ...

  3. Spring Boot 2.3.0正式发布:优雅停机、配置文件位置通配符新特性一览

    当大潮退去,才知道谁在裸泳..关注公众号[BAT的乌托邦]开启专栏式学习,拒绝浅尝辄止.本文 https://www.yourbatman.cn 已收录,里面一并有Spring技术栈.MyBatis. ...

  4. C#版本说明

    语言版本 发布时间 .NET Framework要求 Visual Studio版本 C# 1.0 2002.1 .NET Framework 1.0 Visual Studio .NET 2002 ...

  5. 使用QtCreator遇到的一些问题

    0. 背景 最近在学习QtCreator(版本:4.8.1:编译器:MSVC 2017 64-bit),遇到了一些问题,特记录如下.( 1. 引用库 QtCreator可以直接包含Windows.h, ...

  6. CentOS开机启动不了修复

    1,如果启动时进度条,先修改为日志启动 启动后快速按任何键(Enter除外)进入如下界面 在按e进入 选择第二个选项卡 在按e进入将红色部分 rhgb quiet 删除,然后按Enter,在按b重启 ...

  7. html 转义和反转义

    public static void main(String[] args) {// String html = "<img style=\"width: 100%; hei ...

  8. 从安全的角度看待DNS

    以前对DNS(Domain Name System)认识就大概的知道是一个提供域名解析服务,作为互联网的基础设施,任何一个IT人员都会或多或少都接触到DNS,随着我最近的接触不断提高,我发现DNS还是 ...

  9. 题解 洛谷 P2179 【[NOI2012]骑行川藏】

    题意为在满足\(\sum\limits_{i=1}^nk_i(v_i-v_i^\prime)^2s_i\leqslant E_U\)的条件下最小化\(\sum\limits_{i=1}^n\frac{ ...

  10. Dart中final和const关键字

    final和const 如果您从未打算更改一个变量,那么使用 final 或 const,不是var,也不是一个类型. 一个 final 变量只能被设置一次,两者区别在于:const 变量是一个编译时 ...