【问题标题】:How does the Flyweight pattern in Java work with respect to memory management?Java 中的享元模式在内存管理方面是如何工作的?
【发布时间】:2018-04-26 02:13:13
【问题描述】:

我觉得我对设计模式有一个很好的掌握,但是我似乎无法理解一件事,而且在我查看的资源中似乎没有准确地解释它。
这个问题是,考虑到对象是独立的实体,数据如何通用,而不是静态数据?

https://www.tutorialspoint.com/design_pattern/flyweight_pattern.htm

在这个例子中,我无法弄清楚优化发生在哪里,因为看起来好像每次都像往常一样创建对象。

Circle circle = (Circle)ShapeFactory.getCircle(getRandomColor());
circle.setX(getRandomX());
circle.setY(getRandomY());
circle.setRadius(100);
circle.draw();

这个代码块似乎是我最好的猜测,因为第一行从 HashMap 检索具有某种颜色的圆,但这会创建一个新的圆实例,并没有持久引用圆的颜色。
因此,除非我弄错了,否则没有实际的共享数据,所以我不确定这会在创建期间带来哪些好处。

【问题讨论】:

    标签: java design-patterns flyweight-pattern


    【解决方案1】:

    链接示例中的ShapeFactory 将为每种颜色创建一个Circle

    import java.util.HashMap;
    
    public class ShapeFactory {
       private static final HashMap<String, Shape> circleMap = new HashMap();
    
       public static Shape getCircle(String color) {
          Circle circle = (Circle)circleMap.get(color);
    
          if(circle == null) {
             circle = new Circle(color);
             circleMap.put(color, circle);
             System.out.println("Creating circle of color : " + color);
          }
          return circle;
       }
    }
    

    如果不存在具有指定颜色的Circle,它将创建一个新的Circle 对象并将此实例存储在circleMap 哈希图中。如果具有特定颜色的Circle 已经存在,它将从circleMap 返回已经存在的实例。

    这在文中也有解释:

    ShapeFactory 有一个 Circle 的 HashMap,其键是 Circle 对象的颜色。每当有请求向 ShapeFactory 创建一个特定颜色的圆时,它会检查其 HashMap 中的圆对象,如果找到 Circle 的对象,则返回该对象,否则创建一个新对象,存储在 hashmap 中以供将来使用,并返回给客户。

    这在教程中显示的输出中也很明显:

    Creating circle of color : Black
    Circle: Draw() [Color : Black, x : 36, y :71, radius :100
    Creating circle of color : Green
    Circle: Draw() [Color : Green, x : 27, y :27, radius :100
    Creating circle of color : White
    Circle: Draw() [Color : White, x : 64, y :10, radius :100
    Creating circle of color : Red
    Circle: Draw() [Color : Red, x : 15, y :44, radius :100
    Circle: Draw() [Color : Green, x : 19, y :10, radius :100
    Circle: Draw() [Color : Green, x : 94, y :32, radius :100
    Circle: Draw() [Color : White, x : 69, y :98, radius :100
    

    每个颜色的Circle 只创建一次,但修改多次。


    我同意本教程并没有真正展示 Flyweight 的好处。享元的主要目的是将共享状态外部化。我知道的常见示例在文档中使用字符属性。

    您可以将后三个外部化,而不是将CharacterpositionfontsizetextDecoration 结合起来,从而减少每个Character 实例所需的内存:

    这是一些文字。

    在上一行中,单个字符只需要存储它们的位置,但格式相同,因此可以外部化为单个享元对象。

    这是一些粗体文字。

    在上面的行中,你有两个flyweights。一个用于常规文本,另一个用于四个粗体字符实例。

    【讨论】:

    • 我不明白这会给你带来什么好处。 OP 中块的第一行将圆创建为哈希图中的圆的副本,这意味着每个圆对象都是不同的对象。因此,您将拥有不共享任何数据的对象的多个副本,因此在内存中的大小相同。这只是模式的一个坏例子吗?
    • @Andrew 我不确定你为什么认为它会创建一个副本?但这肯定是一个不好的例子,因为享元的目的是外部化共享状态,享元对象本身应该是不可变的值对象。
    • 别介意我很笨,我忘记了 Java 通过引用复制
    • 对此进行进一步阅读,但最好认为 Java 通过别名进行复制。按引用和按值都有不同的语义,与 Java 的行为不完全匹配。
    猜你喜欢
    • 1970-01-01
    • 2014-03-22
    • 2013-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-10
    • 1970-01-01
    • 2011-01-14
    相关资源
    最近更新 更多