Java 中的 Flyweight 设计模式

今天,我们将探讨FlyWeight设计模式。

FlyWeight设计模式

根据GoF的说法,飞量级设计模式 的意图是:

使用共享高效支持海量细粒度对象

FlyWeight设计模式是一种结构化设计模式 ,就像Facade patternAdapter Pattern一样。当我们需要创建一个类的大量对象时,使用FlyWeight设计模式。由于每个对象都会消耗内存空间,而内存空间对低内存设备(如移动设备或嵌入式系统)至关重要,因此可以应用轻量级设计模式通过共享对象来减少内存负载。在应用FlyWeight设计模式之前,我们需要考虑以下因素:

  • 应用程序要创建的对象数量应该很大。
  • 对象创建占用大量内存,而且可能也很耗时。
  • 对象属性可分为内部属性和外部属性,对象的外部属性应由客户端程序定义。

要应用FlyWeight模式,我们需要将对象属性分为内在 和** 外在** 属性。内部属性使对象具有唯一性,而外部属性由客户端代码设置并用于执行不同的操作。例如,对象圆可以具有颜色和宽度等外部属性。为了应用FlyWeight模式,我们需要创建一个返回共享对象的** FlyWeight工厂** 。在我们的示例中,假设我们需要创建一幅带有线条和椭圆的图形。所以我们会有一个接口Shape,它的具体实现是LineOval。Oval类将具有内部属性来确定是否使用给定的颜色填充Oval,而Line将不具有任何内部属性。

FlyWeight设计模式接口和具体类

‘Shape.java’,你知道的。

 1package com.journaldev.design.flyweight;
 2
 3import java.awt.Color;
 4import java.awt.Graphics;
 5
 6public interface Shape {
 7
 8    public void draw(Graphics g, int x, int y, int width, int height,
 9    		Color color);
10}

Line.java

 1package com.journaldev.design.flyweight;
 2
 3import java.awt.Color;
 4import java.awt.Graphics;
 5
 6public class Line implements Shape {
 7
 8    public Line(){
 9    	System.out.println("Creating Line object");
10    	//adding time delay
11    	try {
12    		Thread.sleep(2000);
13    	} catch (InterruptedException e) {
14    		e.printStackTrace();
15    	}
16    }
17    @Override
18    public void draw(Graphics line, int x1, int y1, int x2, int y2,
19    		Color color) {
20    	line.setColor(color);
21    	line.drawLine(x1, y1, x2, y2);
22    }
23
24}

Oval.java

 1package com.journaldev.design.flyweight;
 2
 3import java.awt.Color;
 4import java.awt.Graphics;
 5
 6public class Oval implements Shape {
 7    
 8    //intrinsic property
 9    private boolean fill;
10    
11    public Oval(boolean f){
12    	this.fill=f;
13    	System.out.println("Creating Oval object with fill="+f);
14    	//adding time delay
15    	try {
16    		Thread.sleep(2000);
17    	} catch (InterruptedException e) {
18    		e.printStackTrace();
19    	}
20    }
21    @Override
22    public void draw(Graphics circle, int x, int y, int width, int height,
23    		Color color) {
24    	circle.setColor(color);
25    	circle.drawOval(x, y, width, height);
26    	if(fill){
27    		circle.fillOval(x, y, width, height);
28    	}
29    }
30
31}

请注意,我在创建具体类的对象时引入了延迟,以表明flyweight模式可以用于实例化时花费大量时间的对象。

飞量级工厂

客户端程序将使用FlyWeight工厂来实例化对象,因此我们需要在工厂中保留客户端应用程序不应该访问的对象的映射。每当客户端程序调用获取Object的实例时,都应该从HashMap返回它,如果没有找到,则创建一个新对象并放入Map中,然后返回它。我们需要确保在创建对象时考虑了所有的内在属性。我们的轻量级工厂类看起来像下面的代码。ShapeFactory.java

 1package com.journaldev.design.flyweight;
 2
 3import java.util.HashMap;
 4
 5public class ShapeFactory {
 6
 7    private static final HashMap<ShapeType,Shape> shapes = new HashMap<ShapeType,Shape>();
 8
 9    public static Shape getShape(ShapeType type) {
10    	Shape shapeImpl = shapes.get(type);
11
12    	if (shapeImpl == null) {
13    		if (type.equals(ShapeType.OVAL_FILL)) {
14    			shapeImpl = new Oval(true);
15    		} else if (type.equals(ShapeType.OVAL_NOFILL)) {
16    			shapeImpl = new Oval(false);
17    		} else if (type.equals(ShapeType.LINE)) {
18    			shapeImpl = new Line();
19    		}
20    		shapes.put(type, shapeImpl);
21    	}
22    	return shapeImpl;
23    }
24    
25    public static enum ShapeType{
26    	OVAL_FILL,OVAL_NOFILL,LINE;
27    }
28}

注意在getShape方法中使用了Java EnumJava Composition(形状图)和工厂pattern

FlyWeight设计模式客户端示例

下面是一个使用FlyWeight模式实现的示例程序。DrawingClient.java

 1package com.journaldev.design.flyweight;
 2
 3import java.awt.BorderLayout;
 4import java.awt.Color;
 5import java.awt.Container;
 6import java.awt.Graphics;
 7import java.awt.event.ActionEvent;
 8import java.awt.event.ActionListener;
 9
10import javax.swing.JButton;
11import javax.swing.JFrame;
12import javax.swing.JPanel;
13
14import com.journaldev.design.flyweight.ShapeFactory.ShapeType;
15
16public class DrawingClient extends JFrame{
17
18    private static final long serialVersionUID = -1350200437285282550L;
19    private final int WIDTH;
20    private final int HEIGHT;
21
22    private static final ShapeType shapes[] = { ShapeType.LINE, ShapeType.OVAL_FILL,ShapeType.OVAL_NOFILL };
23    private static final Color colors[] = { Color.RED, Color.GREEN, Color.YELLOW };
24    
25    public DrawingClient(int width, int height){
26    	this.WIDTH=width;
27    	this.HEIGHT=height;
28    	Container contentPane = getContentPane();
29
30    	JButton startButton = new JButton("Draw");
31    	final JPanel panel = new JPanel();
32
33    	contentPane.add(panel, BorderLayout.CENTER);
34    	contentPane.add(startButton, BorderLayout.SOUTH);
35    	setSize(WIDTH, HEIGHT);
36    	setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
37    	setVisible(true);
38
39    	startButton.addActionListener(new ActionListener() {
40    		public void actionPerformed(ActionEvent event) {
41    			Graphics g = panel.getGraphics();
42    			for (int i = 0; i < 20; ++i) {
43    				Shape shape = ShapeFactory.getShape(getRandomShape());
44    				shape.draw(g, getRandomX(), getRandomY(), getRandomWidth(),
45    						getRandomHeight(), getRandomColor());
46    			}
47    		}
48    	});
49    }
50    
51    private ShapeType getRandomShape() {
52    	return shapes[(int) (Math.random() * shapes.length)];
53    }
54
55    private int getRandomX() {
56    	return (int) (Math.random() * WIDTH);
57    }
58
59    private int getRandomY() {
60    	return (int) (Math.random() * HEIGHT);
61    }
62
63    private int getRandomWidth() {
64    	return (int) (Math.random() * (WIDTH / 10));
65    }
66
67    private int getRandomHeight() {
68    	return (int) (Math.random() * (HEIGHT / 10));
69    }
70
71    private Color getRandomColor() {
72    	return colors[(int) (Math.random() * colors.length)];
73    }
74
75    public static void main(String[] args) {
76    	DrawingClient drawing = new DrawingClient(500,600);
77    }
78}

我已经使用随机数generation在我们的框架中生成了不同类型的形状。如果您运行上面的客户端程序,您将注意到创建First Line对象和Oval对象时的延迟,其中Fill为True和False。在此之后,程序会快速执行,因为它使用的是共享对象。在多次点击)](https://journaldev.nyc3.digitaloceanspaces.com/2013/07/flyweight-pattern-example.png),您将在命令行中看到以下输出,确认对象是共享的。

1Creating Line object
2Creating Oval object with fill=true
3Creating Oval object with fill=false

以上就是FlyWeight模式,我们将在以后的帖子中研究更多的设计模式。如果你喜欢它,请在评论区分享你的想法,并与其他人分享。

JDK中的FlyWeight设计模式示例

所有的wrapper classesvalueOf()方法都使用缓存的对象来展示FlyWeight设计模式的使用。最好的例子是JAVA StringSTRING Pool实施。

FlyWeight设计模式要点

1.在我们的示例中,不强制客户端代码使用FlyWeight工厂创建对象,但我们可以强制这样做,以确保客户端代码使用FlyWeight模式实现,但这是特定应用程序的完整设计决策。 2.FlyWeight模式引入了复杂性,如果共享对象的数量很大,那么就会在内存和时间之间进行权衡,所以我们需要根据自己的需求来明智地使用它。 3.当对象的固有属性数量巨大时,FlyWeight模式实现没有用处,使得Factory类的实现变得复杂。

这就是Java中Flyweight设计模式的全部内容。

Published At
Categories with 技术
comments powered by Disqus