A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 周万谋 中级黑马   /  2012-10-26 16:04  /  1655 人查看  /  3 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 周万谋 于 2012-10-28 15:15 编辑

享元模式是将很多个很小的对象变成一个对象,并把他们不同的属性变成方法的参数。但在复习时对享元模式还不是很理解,请问具体是怎么实现的?

评分

参与人数 1技术分 +1 收起 理由
韩军博 + 1 很给力!

查看全部评分

3 个回复

正序浏览
范贞亮 发表于 2012-10-26 21:54
所谓亨元,就是被其它对象共享使用的
对象。通过这种方式,系统减少了内存的占用。比如一个系统有一个成百 ...

谢谢两位的指导,消化中
回复 使用道具 举报
所谓亨元,就是被其它对象共享使用的
对象。通过这种方式,系统减少了内存的占用。比如一个系统有一个成百上千、
成千上万的小对象,这些小对象可能拥有着共同的信息,那么这些共同的信息就
没有必要也重复成千上万次。把这些共同信息抽取出来,形成一个对象,即是亨
元。这些成千上万的其它对象只需要引用这个亨元即可。

举个例子,在棋类程序中,有时候我们会把一个棋子当成为一个对象。这个对象
包含着位置信息、字体信息、颜色信息、样式信息等。如下所示,
class 棋子{
  public 名字(车、马、炮等)
  public 位置信息
  public 字体信息
  public 颜色信息
  public 样式信息
}

如果我们每次new一个这样的对象,它所占用的内存是这些信息所占内存的和。
new 10个这样的对象就需要10倍的内存占用。实际上,在象棋中,除了象棋棋子
的名字不同、位置不同外,其它的字体信息、样式信息一般都是一样的。比如红
方的棋子是红色、隶书、字体有阴影效果,黑方的棋子是黑色、隶书、有阴影效
果。

这些字体信息、颜色信息、样式信息都可以做成亨元。拿颜色信息来说,如果不
使用亨元,则每一个棋子都要分别创建一个颜色对象,10个棋子就创建10个颜色
对象,而这10个颜色对象很可能是一样的,比如都是红色。这样就太浪费内存了。
使用亨元,则可以避免这种重复创建相同对象的问题。

我们只需要创建一个红色信息的对象,而让所有红色棋子都引用这个红色对象。
同理,让所有黑色棋子都引用黑色对象。这样就减少了内存使用。

比如,我们在new 一个红色棋子对象时,要先去一个颜色信息池中区查找是否已
经有这么一个红色对象,有则,直接引用它,没有则先创建它再引用它。所谓颜
色信息池,一般都用Map来实现。比如,
Map h = new HashMap();
if(h.get("red")!=null){
    h.pub("red",new Color对象);
}else{
    取出这个Color对象(我们叫它objectC)。
}
然后你在另一个地方把这个objectC赋给棋子对象,比如用这种方式:
棋子对象.颜色信息=objectC;
实际上,针对象棋这个例子也没有必要用一个pool来保存Color对象,也没有必要
判断这个对象是不是在pool中存在,也没必要在判断完是否存在后再进行是否生
成一个新对象的工作。因为象棋中无非两种对象,红和黑,这是确定的。所以我
们完全可以把这两个对象提前生成出来,放到一个地方保存着,别人都对它们进
行引用即可,可以这样做,
class 棋子{
    private static Color redColor = new Color("red");
    private static Color blackColor = new Color("black");
...
...      
}
这好像有点单态模式的感觉。实际上,一个class会共享很多实例而不像单态那样
只允许共享一个实例,也不像象棋这样只有红、黑两种颜色对象。假如一个应用
中,class共享的颜色对象可能除了红、黑,还有其它上百种颜色,而且颜色种类
的增减,依赖于用户的操作,那么用一个pool把它们存放起来就比较好。
回复 使用道具 举报
那就从老师讲的例子开始入手:
例如:  Integer number1 = 13;
       Integer number2 = 13;
       System.out.println(number1==number2);
打印的结果却是ture;说明number1和number2是同一个对象,但是当赋值的数字大于127后,结果就是false了.这说明:对于基本数据类型的整数装箱成为Integer类型的对象时,如果这个整数在一个字节之内,也就是在-128~127之间,那么就想把这个封装好的Integer对象放到一个缓冲池中,如果下次再用到这个对象,就直接从缓存池中拿来用,这样就节省了空间.
        对于计算机而言,它认为像这样的小数出现的次数会很多(即使用的频率高),所以将他们共用一个对象,否则,用到一个就会创建一个对象,浪费了空间.
        当一个对象很小,又在多个地方使用,并且对它的使用都是一样的,这时就可以只创建一个这样的对象,其他地方使用时,也就使用这个对象.这种思想就是享元模式.
        享元模式在word中也有体现:在word中会出现很多一样的英文字符,如果写一个字符就创建一个对象,那么word中就会有很多个小对象,会占据很多的空间.所以如果就创建26个对象分别指向这些字符,对于这些字符,唯一不同的就是在word中的位置不同而已.
        例如:字符i,要显示不同位置的i字符就可以这样表述:
           I.display(int x,int y)这样就可以大大的节省空间
总结:享元模式就是:当有很多个小的对象,它们有很多相同的属性,那么就可以把它们变成一个对象,那些不同的属性把它变成方法的参数传入(称为外部状态),那些相同的属性称为这个对象的内部参数.
希望对你有用
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马