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方法,注:该方法只能用于比较简单的类,只能实现浅拷贝,如果类中包含数组等引用类型,则需要使用序列化方法来实现类型的深拷贝
发哥讲
如果你觉得文章还不错,就请点击右上角选择发送给朋友或者转发到朋友圈~
● 扫码关注公众号, 转载请备注来源,和链接
最新文章
- 获取bing.com的图片并在gnome3中设置自动切换
- 如何从零基础学习VR
- sql server ,OVER(PARTITION BY)函数用法,开窗函数,over子句,over开窗函数
- PLSQL_Oracle Object所有数据库对象类型汇总和简解(概念)
- Initializing nested object properties z
- dp题目
- 10055 - Hashmat the Brave Warrior
- Spring4.0学习笔记(11) —— Spring AspectJ 的五种通知
- Agg vs. Cairo 二维绘图引擎之比较和选择 .
- 蓝桥杯PREV-11:横向打印二叉树
- SpringMVC(一):搭建一个SpringMVC helloword项目
- golang string和[]byte的对比
- Linux 下SVN报错No repository found in 'svn://210.16.191.230/huandong_project'
- emacs org-mode文件转html文件
- HihoCoder - 1498 Diligent Robots
- data-original
- 微服务之springCloud-docker-feign(四)
- 老刘 Yii2 源码学习笔记之 Action 类
- delphi中Case语法的使用方法
- C# Winform 跨线程更新UI控件常用方法汇总
热门文章
- 数据可视化之powerBI基础(二)PowerBI动态图表技巧:钻取交互
- Linux07 /redis的配置、五大数据类型、发布订阅、持久化、主从复制、哨兵配置、集群搭建
- 小白从零开始阿里云部署react项目+node服务接口(二:node服务+web)
- springboot整合Druid(德鲁伊)配置多数据源数据库连接池
- python-多任务编程01-线程(threading)
- Kafka 入门(二)--数据日志、副本机制和消费策略
- jsp课堂笔记5 Java servlet
- Java基础加强笔记——测试、反射、注解
- 4. JSON字符串是如何被解析的?JsonParser了解一下
- 彻底弄懂angularJS表单验证