7、Prototype 原型模式 通过复制创造实例 创造型模式
其实上一节的末尾讲到如何去生成对象,其中有一个关于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 原型模式 通过复制创造实例 创造型模式的更多相关文章
- 8、Builder 建造者模式 组装复杂的实例 创造型模式
1.什么是Builder模式 定义: 将一个复杂对象的构建与表示相分离,使得同样的构建过程可以创建不同的表示.大白话就是,你不需要知道这个类的内部是什么样的,只用把想使用的参数传进去就可以了,达到了解 ...
- [WCF编程]7.实例上下文模式
一.实例上下文模式概述 实例上下文(IntanceContext Mode)表示服务端的服务实例与客户端的服务代理的绑定方式. 在实例化服务器对象时,WCF采用了3种不同的模式:单调(Per-Call ...
- C++设计模式-Prototype原型模式
作用: 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. Prototype模式提供了一个通过已存在对象进行新对象创建的接口(Clone), Clone()实现和具体的语言相关,在C+ ...
- 设计模式(五):PROTOTYPE原型模式 -- 创建型模式
1.定义 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 2.适用场景 原型模式的主要思想是基于现有的对象克隆一个新的对象出来,一般是有对象的内部提供克隆的方法,通过该方法返回一个对 ...
- js原生设计模式——7原型模式之真正的原型模式——对象复制封装
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8&qu ...
- 设计模式(1)--Prototype(原型模式)--创建型
1.模式定义: 原型模式就是用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象. 2.使用场景: 在原型模式中我们可以利用过一个原型对象来指明我们所要创建对象的类型,然后通过复制这个对象的 ...
- Java设计模式:Prototype(原型)模式
概念定义 使用原型实例指定待创建对象的种类,并通过拷贝该原型来创建新的对象.Prototype模式允许一个原型对象克隆(复制)出多个与其相同的对象,而无需知道任何如何创建的细节. 应用场景 对象的创建 ...
- 一天一个设计模式——Prototype 原型模式
一.模式说明 看了比较多的资料,对原型模式写的比较复杂,个人的理解就是模型复制,根据现有的类来直接创建新的类,而不是调用类的构造函数. 那为什么不直接调用new方法来创建类的实例呢,主要一个原因是如果 ...
- prototype原型模式中的问题
对于每个构造函数来说,都有一个prototype属性.对于每个对象实例来说,都有_proto_属性. 参看下面代码: function Person(){} Person.prototype={ na ...
随机推荐
- web 部署专题(三):压力测试(一)工具 siege
1.介绍 Siege是一个压力测试和评测工具,设计用于WEB开发这评估应用在压力下的承受能力:可以根据配置对一个WEB站点进行多用户的并发访问,记录每个用户所有请求过程的相应时间,并在一定数量的并发访 ...
- 可能这是Redis可视化工具最全的横向评测
1 命令行 不知道大家在日常操作redis时用什么可视化工具呢? 以前总觉得没有什么太好的可视化工具,于是问了一个业内朋友.对方回:你还用可视化工具?直接命令行呀,redis提供了这么多命令,操作起来 ...
- Newbe.Claptrap 框架入门,第二步 —— 简单业务,清空购物车
接上一篇 Newbe.Claptrap 框架入门,第一步 —— 创建项目,实现简易购物车 ,我们继续要了解一下如何使用 Newbe.Claptrap 框架开发业务.通过本篇阅读,您便可以开始尝试使用 ...
- 【JVM之内存与垃圾回收篇】运行时数据区概述及线程
运行时数据区概述及线程 前言 本节主要讲的是运行时数据区,也就是下图这部分,它是在类加载完成后的阶段 当我们通过前面的:类的加载-> 验证 -> 准备 -> 解析 -> 初始化 ...
- 面试题二十二:链表中倒数第k个节点
方法一:双指针法定义两个指针A.B,A先走k-1步后再一起走,直到A.next==null注意: 1.链表为空 2.链表长度小于k 3.k<=0 当题目是求链表的中间节点时,可以两个指针从开头开 ...
- 如何利用Gitlab-ci持续部署到远程机器?
长话短说,今天聊一聊使用Gitlab-CI 自动部署到远程服务器. 如果看过<>这篇文章的朋友,会注意到我是在 Gitlab-Runner服务器上自动部署的站点,本次我们结合ssh部署到远 ...
- LevelDB,你好~
LevelDB,你好~ 上篇文章初识:LevelDB介绍了啥是LevelDB,LevelDB有啥特性,以及Linux环境下编译,使用及调试方法. 这篇文章的话,算是LevelDB源码学习的开端吧,主要 ...
- 互联网找的e是无理数的初等证明
e的两种计算方式 \(e=lim_{n \to \infty}(1+\frac{1}{n})^n\) \(e=\sum_{n=0}^{+\infty}\frac{1}{n!}\) \(即,e=\fra ...
- 扫描PDF417崩溃的原因找到:手机摄像头分辨率低
换孩子姥姥华为手机解决了. 能扫pdf417码了
- Python延迟初始化(lazy property)
转自:https://blog.csdn.net/azsx02/article/details/77649527 Python 对象的延迟初始化是指,当它第一次被创建时才进行初始化,或者保存第一次创建 ...