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方法,注:该方法只能用于比较简单的类,只能实现浅拷贝,如果类中包含数组等引用类型,则需要使用序列化方法来实现类型的深拷贝

发哥讲

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

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

最新文章

  1. 获取bing.com的图片并在gnome3中设置自动切换
  2. 如何从零基础学习VR
  3. sql server ,OVER(PARTITION BY)函数用法,开窗函数,over子句,over开窗函数
  4. PLSQL_Oracle Object所有数据库对象类型汇总和简解(概念)
  5. Initializing nested object properties z
  6. dp题目
  7. 10055 - Hashmat the Brave Warrior
  8. Spring4.0学习笔记(11) —— Spring AspectJ 的五种通知
  9. Agg vs. Cairo 二维绘图引擎之比较和选择 .
  10. 蓝桥杯PREV-11:横向打印二叉树
  11. SpringMVC(一):搭建一个SpringMVC helloword项目
  12. golang string和[]byte的对比
  13. Linux 下SVN报错No repository found in 'svn://210.16.191.230/huandong_project'
  14. emacs org-mode文件转html文件
  15. HihoCoder - 1498 Diligent Robots
  16. data-original
  17. 微服务之springCloud-docker-feign(四)
  18. 老刘 Yii2 源码学习笔记之 Action 类
  19. delphi中Case语法的使用方法
  20. C# Winform 跨线程更新UI控件常用方法汇总

热门文章

  1. 数据可视化之powerBI基础(二)PowerBI动态图表技巧:钻取交互
  2. Linux07 /redis的配置、五大数据类型、发布订阅、持久化、主从复制、哨兵配置、集群搭建
  3. 小白从零开始阿里云部署react项目+node服务接口(二:node服务+web)
  4. springboot整合Druid(德鲁伊)配置多数据源数据库连接池
  5. python-多任务编程01-线程(threading)
  6. Kafka 入门(二)--数据日志、副本机制和消费策略
  7. jsp课堂笔记5 Java servlet
  8. Java基础加强笔记——测试、反射、注解
  9. 4. JSON字符串是如何被解析的?JsonParser了解一下
  10. 彻底弄懂angularJS表单验证