高效飞快地生成类的实例以提高性能称为享元模式。它是结构设计模式之一,常常被使用在独特的字符或是屏幕上的图标等。
使用场合和优势:
- 需要实例化大量小型且可以很好颗粒化的类。
- 需要图标来展示对象。
- 一个对象外部的状态能够通过类来共享。
- 享元模式减少了对象的创建,降低了内存的花费和提升了性能。
相关的模式:
- 组合模式支持迭代的结构而一个享元仅仅被应用到一个对象。
- 抽象工厂模式基于方法的集合去产生具体的对象而一个享元则是使用它来减少对象的创建。
- 策略模式允许一个独立变化的算法去适合它的需要而一个享元是基于这样的一个策略而已。
下面,我们结合工厂模式来写一个简单的示例程序。
我们扩展了java GUI API,在window面板上绘制小的圆圈。通过使用享元模式,大大提高了程序的性能。
public class Flyweight extends JFrame{
//define the color array
private static final Color colors[] = {
Color.red, Color.green, Color.blue,
Color.black, Color.gray, Color.orange
};
private static final int WIDTH = 400,
HEIGHT = 400,
NUMBER_OF_CIRCLES = 1000;
Flyweight(){
Container container = this.getContentPane();
Button button = new Button("Draw Circle");
final JPanel panel = new JPanel();
//add the components to the container
container.add(panel, BorderLayout.CENTER);
container.add(button, BorderLayout.SOUTH);
//set the properties of JFrame
this.setSize(WIDTH, HEIGHT);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
//add the listener
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Graphics g = panel.getGraphics();
for(int i = 0; i < NUMBER_OF_CIRCLES; i++){
Circle c= CircleFactory.getInstance(getRandomColor());
c.draw(g, getRandomX(), getRandomY(), getRandomR());
//Since we have 6 different colors, we have 6 objects 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));
}
//get the random color
private Color getRandomColor(){
return colors[(int)(Math.random()*(colors.length))];
}
//text the case
public static void main(String []args){
new Flyweight();
/**
String s1 = "hello";
String s2 = "hello"; //store in a string pool.
String s3 = new String("hello");
System.out.println(s1==s2); //true, share the same memmory address
System.out.println(s1==s3); //false
* */ }}
public class CircleFactory {
private static final Hashtable<Color, Circle> circleByColor = new Hashtable<Color, Circle>();
public static Circle getInstance(Color color) {
Circle circle = (Circle) circleByColor.get(color);
if (circle == null) {
circle = new Circle(color);
circleByColor.put(color, circle);
System.out.println("---------create " + circle + " color");
}
return circle;
}
}
Circle类定义
public class Circle {
private Color color;
Circle(Color color){
this.color = color;
}
public void draw(Graphics g, int a, int b, int r){
g.setColor(color);
g.drawOval(a, b, r, r);
}
}
运行结果:
细心的朋友一定会注意到最后段注释了代码,说的也是享元的是。String类是采用了享元设计模式。当你创建一个字符串常量时,这样的常量会存储在一个池中。当第二个string被创建时,它将会检测这个常量是否以前创建过。如果string池中有这个常量,它将直接采用这个池中的常量而不会再创建。
String s1 = "hello";
String s2 = "hello"; //store in a string pool.
String s3 = new String("hello");
System.out.println(s1==s2); //true, share the same memmory address
System.out.println(s1==s3); //false