博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java设计模式之原型模式
阅读量:5051 次
发布时间:2019-06-12

本文共 4392 字,大约阅读时间需要 14 分钟。

概论

什么是原型模式呢?用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。这个模式就叫作原型模式。原型模式属于对象创建者模式。

 

原型模式示例

 首先我们需要有一个原型。这个原型实现了Cloneable空接口。这是一个标记接口,并无任何的方法。

1 package com.example.pattern.prototype; 2  3 import lombok.*; 4  5 import java.io.Serializable; 6 import java.util.Arrays; 7 import java.util.List; 8  9 @Setter10 @Getter11 @NoArgsConstructor12 @AllArgsConstructor13 public class PrototypeClass implements Cloneable {14 15     private int id;16     private char code;17     private String name;18 19     private BaseDomain baseDomain;20     private String[] array;21 22     private List
list;23 24 25 @Override26 protected PrototypeClass clone() {27 PrototypeClass prototypeClass = null;28 29 try {30 prototypeClass = (PrototypeClass) super.clone();31 } catch (CloneNotSupportedException e) {32 e.printStackTrace();33 34 }35 36 return prototypeClass;37 }38 39 40 }

第9行-12行:采用lambok注解,简化了简单对象中的繁琐的get,set,带所有参数的构造函数,无参构造函数。

第15-22行:定义了类型为原子类型,复杂对象,已经数组和集合的成员属性。

 

最后,我们需要增加一个场景类Client:

1 public class Client { 2  3     public static void main(String[] args) { 4         PrototypeClass prototypeClass = new PrototypeClass(); 5         prototypeClass.setId(123); 6         prototypeClass.setCode('A'); 7         prototypeClass.setName("Tom"); 8         prototypeClass.setBaseDomain(new BaseDomain()); 9 10         String[] array = new String[]{"22222"};11         prototypeClass.setArray(array);12 13         List
list = new ArrayList
();14 list.add("CCC");15 prototypeClass.setList(list);16 17 PrototypeClass cloneClass = prototypeClass.clone();18 19 cloneClass.setId(456);20 cloneClass.setCode('B');21 cloneClass.setName("Jack");22 23 System.out.println("prototypeClass.getId() :"+prototypeClass.getId());24 System.out.println("cloneClass.getId():"+cloneClass.getId());25 26 System.out.println("prototypeClass.getCode() :"+prototypeClass.getCode());27 System.out.println("cloneClass.getCode():"+cloneClass.getCode());28 29 System.out.println("prototypeClass.getName() :"+prototypeClass.getName());30 System.out.println("cloneClass.getName():"+cloneClass.getName());31 32 String[] array2 = new String[]{"33333"};33 cloneClass.setArray(array);34 35 List
list2 = new ArrayList
();36 list.add("DDDD");37 cloneClass.setList(list);38 39 40 System.out.println("prototypeClass.getList().get(0) :"+prototypeClass.getList().get(0));41 System.out.println("cloneClass.getList().get(0) :"+cloneClass.getList().get(0));42 43 System.out.println("prototypeClass.getArray()[0] :"+prototypeClass.getArray()[0]);44 System.out.println("cloneClass.getArray()[0] :"+cloneClass.getArray()[0]);45 46 47 48 }49 }

第17行:调用了对象的clone方法,直接产生一个对象。这就是对象的复制,而不是使用new 指令。使用对象复制的方式,不会调用构造函数。

我们先执行一下打印出来的结果:

1 prototypeClass.getId() :123 2 cloneClass.getId():456 3 prototypeClass.getCode() :A 4 cloneClass.getCode():B 5 prototypeClass.getName() :Tom 6 cloneClass.getName():Jack 7 prototypeClass.getList().get(0) :CCC 8 cloneClass.getList().get(0) :CCC 9 prototypeClass.getArray()[0] :2222210 cloneClass.getArray()[0] :22222

 从以上执行结果来看

①:如果成员属性为int char String类型,复制后的对象的属性的改变不会对原始对象的属性产生任何的影响。

②:如果成员属为是List集合,数组,复制后的对象的属性的改变也会和原始对象的属性产生了影响。

这是为什么呢?因为我们在原型中的拷贝方式是浅拷贝。什么是浅拷贝呢?super.clone是谁的方法呢,当然是Object方法的,因为Object是任何类的超类。而Object类提供的clone方法只是拷贝本对象,这个对象的内部成员属性包括数组,集合,引用对象都不拷贝,还是执行原生对象的内部元素地址。因此数组,集合,引用对象都是在原生对象还是拷贝对象中都是共享而存在的。这就是浅拷贝。

 

浅拷贝的对象中的成员属性还有对象的情况下, 像以上例子中的 BaseDomain。改变了同一个BaseDomian实例的属性name的情况下, 因为是同一个实例,因此也是共享的,一边都变。如果是重新new一个BaseDomain实例,重新对拷贝之后的对象复制,那是互相不干扰的。 

 

原型模式在源码中的应用

1 public Object clone() { 2         try { 3             ArrayList
v = (ArrayList
) super.clone(); 4 v.elementData = Arrays.copyOf(elementData, size); 5 v.modCount = 0; 6 return v; 7 } catch (CloneNotSupportedException e) { 8 // this shouldn't happen, since we are Cloneable 9 throw new InternalError(e);10 }11 }

以上是ArrayList的clone方法,我们可以产生了一个list之后,来clone一下,来简化操作,这里用到的是深拷贝。为什么是深拷贝而不是浅拷贝呢?第4-行-5行数组,修改次数再复制,拷贝之后的对象与原来的对象不再持有同一份引用,因此是深拷贝。而且Arrays.copyOf方法中是重新创建的一个新数组。

 

转载于:https://www.cnblogs.com/sunshine798798/p/10057365.html

你可能感兴趣的文章
二分图匹配 学习笔记
查看>>
poj 2154:Color【polya计数,Euler函数】
查看>>
【转】前台和后台线程
查看>>
洛谷 P1964 【mc生存】卖东西
查看>>
纯CSS制作自适应分页条-分享------彭记(019)
查看>>
VS WebDev.WebServer40
查看>>
openjudge 2971:抓住那头牛 解题报告
查看>>
如何实现redis集群?
查看>>
架构中的集成难点
查看>>
正则表达式
查看>>
liunx系统虚拟机下安装tomcat9以及访问tomcat案例
查看>>
Oracle 插入Date数据
查看>>
word文档操作
查看>>
UIpageControl
查看>>
js判断是否为IE浏览器,是返回true,否返回false
查看>>
Linux性能分析 vmstat基本语法
查看>>
SpringMVC框架学习笔记(2)——使用注解开发SpringMVC
查看>>
深入理解递归函数的调用过程
查看>>
《在C#中实现Socket端口复用》 以及《 UDP 一个封锁操作被对 WSACancelBlockingCall 的调用中断。》问题...
查看>>
PDF格式的“在线阅读”和“下载”
查看>>