先从一张图说起,剩下的就靠写了...设计模式文章合集:http://aphysia.cn/categories/...前言接触过Spring的小伙伴或者Springboot同学可能都知道Bean默认是单例的,也就是全局共享同一个对象,不会因为不同的请求而使用不同的对象。我们不会在这里讨论单例。单例模式的好处和各种有兴趣的可以了解一下:http://aphysia.cn/archives/de...。除了单例,Spring还可以设置其他作用域,即scope="prototype",即原型模式。每次请求到来时,都会创建一个新对象。该对象是根据原型实例创建的。原型模式的定义原型模式也是创建模式的一种,是指用一个原型实例指定要创建的对象的类型,通过复制这些原型来创建一个新的对象。简单来说,就是抄袭。一般适用于:实例比较复杂,全量创建成本高,直接复制比较简单,构造函数比较复杂,创建可能会生成很多不需要的对象优点:隐藏了创建实例的具体细节的时候只有少数属性需要特化,可以直接使用原型模式复制的对象,修改即可达到目的。原型模式的实现一般来说,原型模式是用来复制对象的,所以被复制的对象必须有一个原型类,即Prototype,Prototype需要实现Cloneable接口。只有实现这个接口才能复制,然后重写clone()方法,也可以根据不同的类型快速获取原型对象。我们首先定义了一个原型类Fruit:publicabstractclassFruitimplementsCloneable{Stringname;浮动价格;publicStringgetName(){返回名称;}publicvoidsetName(Stringname){this.name=name;}publicfloatgetPrice(){返回价格;}publicvoidsetPrice(floatprice){this.price=price;}publicObjectclone(){对象克隆=null;试试{clone=super.clone();}catch(CloneNotSupportedExceptione){e.printStackTrace();}返回克隆;}@OverridepublicStringtoString(){return"Fruit{"+"name='"+name+'\''+",price="+price+'}';}}以及拓宽了水果类的实体类Apple,Pear,Watermelon:publicclassAppleextendsFruit{publicApple(floatprice){name="苹果";这个。价格=价格;}}publicclassPearextendsFruit{publicPear(浮动价格){name=“悉尼”;这个。价格=价格;}}publicclassWatermelonextendsFruit{publicWatermelon(floatprice){name="Watermelon";这个。价格=价格;第一次取的时候,根据不同的类型取出来,复制一次返回:static{Appleapple=newApple(10);fruitMap.put(apple.getName(),apple);梨pear=newPear(8);fruitMap.put(pear.getName(),pear);西瓜西瓜=新西瓜(5);水果地图。放(西瓜。getName(),西瓜);}publicstaticFruitgetFruit(Stringname){Fruitfruit=fruitMap.get(name);返回(水果)fruit.clone();}}测试得到不同的Fruit,对比两次获取的同类型,可以发现两次获取的同类型不是同一个对象:publicclassTest{publicstaticvoidmain(String[]args){水果苹果=FruitCache.getFruit("苹果");System.out.println(苹果);水果梨=FruitCache.getFruit("雪梨");System.out.println(梨);水果西瓜=FruitCache.getFruit("西瓜");System.out.println(西瓜);水果apple1=FruitCache.getFruit("苹果");System.out.println("是否是同一个对象"+apple.equals(apple1));}}结果如下:Fruit{name='Apple',price=10.0}Fruit{name='Sydney',price=8.0}Fruit{name='Watermelon',price=5.0}false再测试一下,看看如果里面的name属性是同一个对象:publicclassTest{publicstaticvoidmain(String[]args){Fruitapple=FruitCache.getFruit("apple");System.out.println(苹果);水果apple1=FruitCache.getFruit("苹果");System.out.println(apple1);System.out.println("是否为同一个对象:"+apple.equals(apple1));System.out.println("是否是同一个字符串对象:"+apple.name.equals(apple1.name));}}结果如下,里面的字符串还是使用同一个对象:Fruit{name='apple',price=10.0}Fruit{name='apple',price=10.0}是否是同一个对象:是否为false是同一个字符串对象:true这是为什么?因为上面用的clone()是浅拷贝!!!但是有一点,字符串在Java中是不可变的,如果修改了,原来的字符串不会被修改,由于这个属性的存在,类似于深拷贝。如果该属性是其他自定义对象,那就要注意了。浅拷贝不会真正复制对象,而只是复制一个引用。这里不得不介绍一下浅拷贝和深拷贝的区别:浅拷贝:没有真正的拷贝数据,只是拷贝一个指向数据内存地址的指针深拷贝:不仅新建一个指针,还拷贝一份数据内存如果我们使用Fruitapple=apple1,这只是复制了对象的引用,但本质上仍然是同一个对象。上面情况虽然对象不同,但是Apple属性的副本还是属于同一个引用,地址还是一样的。它们共享原始的属性对象名称。那么如何进行深拷贝呢?一般有以下解决方案:直接新建一个对象,不需要考虑序列化和反序列化:先序列化,再反序列化回来,就可以得到一个新的对象。请注意,必须实现Serializable接口。自己重写对象的clone()方法序列化,实现深拷贝序列化。实现代码如下:创建一个Student类和一个School类:importjava.io.Serializable;publicclassStudentimplementsSerializable{字符串名称;学校学校;publicStudent(Stringname,School学校){this.name=name;this.school=学校;}}导入java.io.Serializable;公共类SchoolimplementsSerializable{Stringname;公立学校(字符串名称){this.name=name;}}序列化复制类:importjava.io.ByteArrayInputStream;importjava.io.ByteArrayOutputStream;importjava.io.ObjectInputStream;importjava.io.ObjectOutputStream;importjava.io.Serializable;publicclassCloneUtil{publicstatic
