上海网站建设高端定制,windows优化大师的功能,2015做哪个网站致富,怎么做淘宝客优惠劵网站今人不见古时月#xff0c;今月曾经照古人 ——李白 文章目录 定义图纸一个例子#xff1a;可以复用的样式表绘制表格降本增效#xff1f;第一步#xff0c;先分析 变化和不变的地方第二步#xff0c;把变化和不变的地方拆开来第三步#xff1a;有没有办法共享这些内容完… 今人不见古时月今月曾经照古人 ——李白 文章目录 定义图纸一个例子可以复用的样式表绘制表格降本增效第一步先分析 变化和不变的地方第二步把变化和不变的地方拆开来第三步有没有办法共享这些内容完全相同的样式对象 碎碎念抽象变化的部分 抽象不变的部分享元和单例享元和String.intern()享元和活字印刷 定义
运用共享技术有效地支持大量颗粒度对象 享元 真是一个非常非常优秀的翻译 如果你单看 四人组 对享元的定义那很容易就会把他理解成类似 连接池 那种对对象进行共享的模式。但是如果享元就是对对象池的管理的话那他的元字如何解释呢窃以为这里的元应该做 【元件】 讲共享元件才叫享元。享元不是对整个大对象进行对象池管理而是对大对象中的重复部分抽离出来进行管理。 图纸 一个例子可以复用的样式表
在 css 中我们会把经常用到的样式组合成一个 css 类然后在标签中通过 classXX 的方式让N个标签引用同样的样式
如果你用过 jxl 或者 poi 这样的框架操作过 Excel 表格的话就会发现你可以在一个 Sheet 里创建的样式是有上限的。可是 C# 里用于操作 office 的框架却没有这个烦恼。当然微软一家亲肯定有一些优化可问题在于他怎么做到的呢
准备好了吗这次的例子开始了 绘制表格
假如我们现在要 绘制一个表格的框架就像这样 //格
public class Cell {//设定字体private Font font;//背景颜色private Color background;//要展示的值private String value;public void draw(){System.out.println(根据fontbackgroundvalue进行绘制);}…… getter setter other 略
}//行
public class Row {private final ListCell cells;public Row(ListCell cells) {this.cells cells;}public void draw(){for (Cell cell : cells) {cell.draw();}}……
}//表
public class Sheet {private final ListRow rows;public Sheet() {rows new ArrayList();}public void draw() {for (Row row : rows) {row.draw();}}……
}这个框架特别好我就喜欢这种一眼能看到头不藏着掖着的框架。这玩意他单纯
可是太单纯也有问题某天我们用他处理一个 1000*10 的表格的时候他直接就崩溃了
经过分析我们发现在绘制表格的时候程序占用的内存异常高10000个格子意味着我们会有10000个cell对象 和 10000个Font对象 以及 10000个Color对象有没有办法简化他 降本增效
重构代码的方式总是大同小异的
第一步先分析 变化和不变的地方
我们发现1000个Row对象和10000个Cell对象 肯定是节约不了的而 Cell 中最关键的 Value 每一格都不相同哪怕碰巧一致不确定性太多无法公用
那就只能从 样式 上打主意了Cell 通过 一个 Font 对象 和 一个 Color 对象来管理 Cell 的样式而一个表格里面字体不超过5种颜色不超过10种。我们却创建了整整 10000 个 Font 对象和 10000 个 Color 对象。这显然是不合理的 第二步把变化和不变的地方拆开来
这一步已经完成了 因为 Cell 和 Font、Color 本来就是通过组合绑定在一起的 第三步有没有办法共享这些内容完全相同的样式对象
当然有
我们可以创建 关于Font的对象池 和 关于Color的对象池然后创建对应的工厂方法要求 client 必须通过工厂方法来获取 Font 和 Color 对象。当我们发现 client 获取已经在池中存在的 Font、Color 对象的时候直接从池里面把 已有对象 返还给 client如果 client 获取的是全新的样式则新建对应的 Font、Color 对象返还给 client并把新建的对象写入池中
就像这样 public class StyleFactory {//字体池private ListFont fontPool new LinkedList();//颜色池private ListColor colorPool new LinkedList();public Font getFont(int size, String fontFamily, Color color) {for (Font font : fontPool) {if (font.getSize() size font.getFontFamily().equals(fontFamily) font.getColor().equals(color)/*Color的equals方法已经重构过了*/) {return font;}}Font result new Font(size, fontFamily, color);fontPool.add(result);return result;}public Color getColor(int red, int green, int blue) {for (Color color : colorPool) {if (color.getRed() red color.getGreen() green color.getBlue() blue) {return color;}}Color result new Color(red, green, blue);colorPool.add(result);return result;}
}我们增加了 fontPool 和 colorPool 这两个列表用于管理程序中已经出现过的 Font、Color对象
然后通过定义 StyleFactory 的方式管理 Font、Color 对象创建的方式同时管理池最终实现相同样式的共享从而大大降低了内存损耗
而这正是一个标准的 享元 实现 为啥要用遍历而不是映射表 因为没必要上文已经讲过 Font 在一个表格中出现次数不超过 5 种Color 不超过 10 种。这种数量级的遍历根本不会对性能产生影响 碎碎念
抽象变化的部分 抽象不变的部分
在之前的设计模式中我们通常是以不变的部分作为基层把变化的部分剥离开来让他去和不变的部分进行组合以实现降低耦合的效果
但享元比较特殊他是少有的剥离不变的部分以变化的部分为基准让变化的部分去找不变的部分的设计模式 享元和单例
如果把享元的内容从对象内的某些状态拓展到整个对象这时候的享元就是对整个对象的对象池管理此时我们甚至可以说单例是极致的享元
但是享元和单例的本质是不同的
单例讲究从根本上只有一个对象而且这一个对象的状态也是共享的部分所以他也应该是可变的享元讲究一种状态一个对象一个享元对象被创建出来后他的状态应该是不可变的。因为当你改变享元对象的状态时所有引用这个对象的外部对象都会因此而改变这并不是我们用享元想要看到的效果。
所以硬要在创建型模式里找一个跟享元像的话倒不如说是原型的思想更像一点
对原型来说创建一个新对象花销太大了那行我不创建了我复制对享元来说大量对象都有 地址不同的相同状态 占用太大了那行别创建了大家都用同一个就完事了 享元和String.intern()
首先我们要知道这个intern方法是用来干嘛的 String 中的 intern() 是一个本地方法他的作用为假如一个字符串在 常量池 中已经存在了则返还常量池中的该字符串如果不存在则把该字符串放入常量池再返还常量池中的该字符串对象的引用 有没有觉得他跟享元超级像其实Java中的String就是用了享元的思想。我们知道String是不可变的我们创建的字符串会被放到某个公共区域常量池以便程序中所有的类共享这些字符串信息。JVM一定要这样管控字符串如果为所有的字符串都创建全新的信息那一下子就爆内存了。
可别认为这只是一个可知可不知的冷知识面试官是很喜欢问问他有关的问题的比如他可以这样问
请问以下代码会如何输出
String str1 new StringBuilder(a).append(b).toString();
System.out.println(str1.intern() str1);String str2 new StringBuilder(ja).append(va).toString();
//String str2 new StringBuilder(a).append(b).toString(); //这样写效果也是一样的
System.out.println(str2.intern() str2);答案是这样的
1.6及以下时输出 false、false1.7及以上时输出 true、false
至于原因咱这是讲设计模式的就不展开了这玩意跟堆 栈 永久代有关系太长了有机会整理JVM的笔记时再唠吧 享元和活字印刷
就是古代四大发明里面哪个活字印刷
仔细想想其实活字印刷就是享元思想的体现
把每个字都制作成小方块放到字库中需要的时候先到字库里面找如果没找到刻一个先用用完再把刚刻好的那个方块放到字库中方便下次调用
古人的智慧真是不可小觑 万分感谢您看完这篇文章如果您喜欢这篇文章欢迎点赞、收藏。还可以通过专栏查看更多与【设计模式】有关的内容