模式定义
Flyweight模式尤其适用于需要创建大量的颗粒对象,而这些对象在某些属性上又极为相似或着能够抽取出相同的属性的情况下,能大幅提高性能减少内存使用。
使用范围
- 需要创建大量的颗粒对象(细微的,但是纹理清晰的)
- 一个对象的外在属性能够抽取出来可供共享的
举例说明
假设需要在一个面板上绘出大量随机的圆圈图像,这些圆圈颜色是随机的,在面板上出现的位置也是随机的。通常的做法是在需要画出圆圈的时候new出一个Circle的实例,在画出来。假设需要画1000个圆圈,就需要创建1000个实例。
package zigzag.designpattern.flyweight; import java.awt.*; import java.awt.Color; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; class Painter extends JFrame{ private static final Color colors[] = { Color.red, Color.blue, Color.yellow, Color.orange, Color.black, Color.white }; private static final int WIDTH = 600, HEIGHT = 400, NUMBER_OF_CIRCLES = 1000; public Painter() { Container contentPane = getContentPane(); JButton button = new JButton("Draw Circle"); final JPanel panel = new JPanel(); contentPane.add(panel, BorderLayout.CENTER); contentPane.add(button, BorderLayout.SOUTH); setSize(WIDTH ,HEIGHT); setTitle("Flightweight demo by ZigzagSoft.net"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { Graphics g = panel.getGraphics(); for(int i=0; i < NUMBER_OF_CIRCLES; ++i) { Circle circle = new Circle(getRandomColor()); circle.draw(g, getRandomX(), getRandomY(), getRandomR());//1000 object created. } } }); } private int getRandomX() { return (int)(Math.random()*WIDTH ); } private int getRandomY() { return (int)(Math.random()*HEIGHT); } private int getRandomR() { return (int)(Math.random()*(HEIGHT/10)); } private Color getRandomColor() { return colors[(int)(Math.random()*colors.length)]; } public static void main(String[] args) { Painter painter = new Painter(); } } class Circle { private Color color; public Circle(Color color) { this.color = color; } public void draw(Graphics g, int x, int y, int r) { g.setColor(color); g.drawOval(x, y, r, r); } }
注意到在按钮事件中,我们循环创建Circle实例,消耗了太多的内存。
for(int i=0; i < NUMBER_OF_CIRCLES; ++i) { Circle circle = new Circle(getRandomColor()); circle.draw(g, getRandomX(), getRandomY(), getRandomR());//1000 object created. }
一个改进的做法是使用Flyweight。我们可以把创建过后的新的Circle存放在一个内存中,下次再次创建的时候,我们无须重新创建,而是每次都从内存中查找是否曾经创建过相同颜色的圆圈,有,则直接取出,否则才创建并保存至内存供下次使用。此处,Circle是一个细微的对象,颜色是它的一个纹理,可供大量共享。因此我们可以使用Singleton模式来维护这个内存的变化。一个改进的模式引入了新类CircleFactory
class CircleFactory { private static final HashMap circleByColor = new HashMap(); public static Circle getCircle(Color color) { Circle circle = (Circle)circleByColor.get(color); if(circle == null) { circle = new Circle(color); circleByColor.put(color, circle); System.out.println("Creating " + color + " circle"); } return circle; } }
同时,创建Circle的方法也需要调整:
for(int i=0; i < NUMBER_OF_CIRCLES; ++i) { Circle circle = CircleFactory.getCircle(getRandomColor()); circle.draw(g, getRandomX(), getRandomY(),getRandomR()); //Since we have 6 different colors, we have 6 objects created. }
下载示例