大家好,我是北军。我相信在你日常的开发过程中,一个优秀的程序员写出的代码一定是节省空间的,比如节省内存,节省磁盘等等。那么如何通过设计模式来节省内存呢?1.享元模式是什么?使用共享来有效地支持大量细粒度对象。享元模式:使用共享对象可以有效支持大量的细粒度对象。说人话:重用对象,节省内存。2.享元模式定义①享元——抽象享元角色是一个产品的抽象类,同时定义了对象的外部状态和内部状态的接口或实现。一个对象的信息可以分为内部状态和外部状态。内部状态:对象可以共享的信息存储在享元对象内部,不会随环境变化。可以作为对象的动态附加信息。不需要直接存储在具体的对象中,是可以共享的部分。外部状态:对象可以依赖的标志,是一种随环境变化而不能共享的状态。②ConcreteFlyweight——享元角色的具体产品类,实现抽象角色定义的业务。这个角色需要注意的是,内部状态处理应该和环境无关,一个操作不能在修改外部状态的同时改变内部状态,这是绝对不允许的。③unsharedConcreteFlyweight——非共享享元角色没有外部状态或安全要求(如线程安全)不能使用共享技术的对象一般不会出现在享元工厂中。④FlyweightFactory——FlyweightFactory的职责很简单,就是构造一个池容器,并提供从池中获取对象的方法。3.享元模式通用代码/***abstract享元角色*/publicabstractclassFlyweight{//内部状态privateStringinstrinsic;//外部状态通过final修改,防止修改protectedfinalStringextrinsic;protectedFlyweight(Stringextrinsic){this.extrinsic=extrinsic;}//定义业务操作publicabstractvoidoperate();publicStringgetInstrinsic(){returninstrinsic;}publicvoidsetInstrinsic(Stringinstrinsic){this.instrinsic=instrinsic;}}/***具体享元角色1*/publicclassConcreteFlyweight1extendsFlyweight{protectedConcreteFlyweight1(Stringextrinsic){super(extrinsic);}@Overridepublicvoidoperate(){System.out.println("具体享元角色1");}}/***具体享元角色2*/publicclassConcreteFlyweight2extendsFlyweight{protectedConcreteFlyweight2(Stringextrinsic){super(extrinsic);}@Overridepublicvoidoperate(){System.out.println("具体享元角色2");}}publicclassFlyweightFactory{//定义一个池容器privatestaticHashMappool=newHashMap<>();//享元工厂publicstaticFlyweightgetFlyweight(Stringextrinsic){//需要返回的对象是享元flyweight=null;//池中没有这样的对象Objectif(pool.containsKey(extrinsic)){flyweight=pool.get(extrinsic);}else{//根据外部状态创建享元对象flyweight=newConcreteFlyweight1(extrinsic);//放入池中pool.put(extrinsic,flyweight);}返回享元;}}4.通过享元设计一个文本编辑器假设文本编辑器只包含文本编辑功能,只记录文本和格式两部分信息,其中格式包括字体型号、字号、颜色等信息4.1通用实现通常的设计是将每个文本视为一个单独的对象。packagecom.itcoke.designpattern.flyweight.edittext;/***单个文本对象*/publicclassCharacter{//字符privatecharc;//字体类型privateStringfont;//字体大小privateintsize;//字体颜色privateintcolorRGB;publicCharacter(charc,Stringfont,intsize,intcolorRGB){this.c=c;this.font=字体;this.size=大小;this.colorRGB=colorRGB;}@OverridepublicStringtoString(){returnString.valueOf(c);}}/***编辑器实现*/publicclassEditor{privateArrayListchars=newArrayList<>();publicvoidappendCharacter(charc,Stringfont,intsize,intcolorRGB){字符character=newCharacter(c,font,size,colorRGB);chars.add(字符);}publicvoiddisplay(){System.out.println(chars);}}client:publicclassEditorClient{publicstaticvoidmain(String[]args){Editoreditor=newEditor();编辑器.appendCharacter('A',"歌曲类型",11,0XFFB6C1);editor.appendCharacter('B',"歌曲类型",11,0XFFB6C1);editor.appendCharacter('C',"歌曲类型",11,0XFFB6C1);编辑器.display();}}4.2享元模式改写上面的问题很容易发现,每个字符都会创建一个Character对象,如果有几百万个字符,那么内存中就会有几百万个对象,那么这些内存怎么保存呢?其实我们分析一下,通常字体格式不多,所以我们可以将字体格式设置为Flyweight,也就是上面说的可以共享的内部状态。内部状态(共享):字体类型、大小、颜色外部状态(不共享):字符所以代码改写如下:publicclassCharacterStyle{//字体模型privateStringfont;//字体大小privateintsize;//字体颜色privateintcolorRGB;publicCharacterStyle(Stringfont,intsize,intcolorRGB){this.font=font;this.size=大小;this.colorRGB=colorRGB;}@Overridepublicbooleanequals(Objecto){if(this==o)returntrue;如果(o==null||getClass()!=o.getClass())返回false;CharacterStyle=(CharacterStyle)o;返回大小==that.size&&colorRGB==that.colorRGB&&Objects.equals(font,that.font);}@OverridepublicinthashCode(){returnObjects.hash(font,size,colorRGB);}}publicclassCharacterStyleFactory{privatestaticfinalMapmapStyles=newHashMap<>();公共静态CharacterStylegetStyle(字符串字体,我ntsize,intcolorRGB){CharacterStylenewStyle=newCharacterStyle(字体,大小,colorRGB);if(mapStyles.containsKey(newStyle)){返回mapStyles.get(newStyle);}mapStyles.put(newStyle,newStyle);返回新样式;}}publicclassCharacter{privatecharc;私有CharacterStyle样式;publicCharacter(charc,CharacterStylestyle){this.c=c;this.style=样式;}@OverridepublicStringtoString(){returnString.valueOf(c);}}publicclassEditor{privateListchars=newArrayList<>();publicvoidappendCharacter(charc,Stringfont,intsize,intcolorRGB){字符character=newCharacter(c,CharacterStyleFactory.getStyle(font,size,colorRGB));chars.add(字符);}publicvoiddisplay(){System.out.println(chars);}}5.享受元模型在java.lang.Integer中应用看下面这段代码,打印结果是啥?publicclassIntegerTest{publicstaticvoidmain(String[]args){Integeri1=56;整数i2=56;整数i3=129;整数i4=129;System.out.println(i1==i2);System.out.println(i3==i4);}}为什么是这个结果?先说Integeri=59;底层实现:Integeri=Integer.valueOf(59);这是自动装箱intj=i;底层实现:intj=i.intValue();这是自动拆箱。然后我们Integer.valueOf()方法:再看IntegerCache源码:privatestaticclassIntegerCache{staticfinalintlow=-128;静态最终int高;静态最终整数缓存[];static{//高值可以由属性配置inth=127;StringintegerCacheHighPropValue=sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");if(integerCacheHighPropValue!=null){try{inti=parseInt(integerCacheHighPropValue);i=Math.max(i,127);//最大数组大小为Integer.MAX_VALUEh=Math.min(i,Integer.MAX_VALUE-(-low)-1);}catch(NumberFormatExceptionnfe){//如果属性无法解析为int,则忽略它。}}高=h;cache=newInteger[(high-low)+1];intj=低;for(intk=0;k=127;}privateIntegerCache(){}}其实这就是我们前面提到的享元对象的工厂类,它缓存了-128到127之间的整数值,这是整数值中最常用的部分,当然,JDK还提供了一个方法让我们可以自定义缓存的最大值6.享元模式的优点减少应用程序创建的对象,减少程序的内存占用,增强程序的性能。但同时也增加了系统的复杂度,需要将外部状态和内部状态分开,并且外部状态具有固定的特性,不应该随着内部状态的变化而变化,否则逻辑上系统会很混乱。7.享元模式应用场景①系统中存在大量相似对象。②细粒度的对象都有一个比较接近的外部状态,内部状态与环境无关,也就是说对象没有特定的身份。③需要缓冲池的场景。