一、享元模式定义

 

以共享的方式高效的支持大量的细粒度对象。通过复用内存中已存在的对象,降低系统创建对象实例的性能消耗。
享元的英文是Flyweight,是一个来自体育方面的专业用语,在拳击、摔跤和举重比赛中特指最轻量的级别。把这个单词移植到软件工程中,也是用来表示特别小的对象,即细粒度的对象。至于为什么把Flyweight翻译为“享元”,可以理解为共享元对象,也就是共享细粒度对象。
在面向对象中,大量细粒度对象的创建、销毁及存储所造成的资源和性能上的损耗,可能会在系统运行时形成瓶颈。那么该如何避免产生大量的细粒度对象,同时又不影响系统使用面向对象的方式进行操作呢?享元模式提供了一个比较好的解决方案。

二、享元模式的角色

抽象享元类(Flyweight)
它是所有具体享元类的超类。为这些类规定出需要实现的公共接口,那些需要外蕴状态(Exte的操作可以通过方法的参数传入。抽象享元的接口使得享元变得可能,但是并不强制子类实行共享,因此并非所有的享元对象都是可以共享的。

具体享元类(FlyWeightAIml,FlyWeightBIml)
具体享元类实现了抽象享元类所规定的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。享元对象的内蕴状态必须与对象所处的周围环境无关,从而使得享元对象可以在系统内共享。有时候具体享元类又称为单纯具体享元类,因为复合享元类是由单纯具体享元角色通过复合而成的。

享元工厂类(FlyweightFactoiy)
享元工厂类负责创建和管理享元对象。当一个客户端对象请求一个享元对象的时候,享元工厂需要检查系统中是否已经有一个符合要求的享元对象,如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有适当的享元对象的话,享元工厂角色就应当创建一个新的合适的享元对象。
客户类(Client)
客户类需要自行存储所有享元对象的外蕴状态。

 通用类图如下:

 首先是享元抽象类:

package com.ssy.wlj.flyweight;

/**
 * FlyWeight 享元抽象类
 * @author Administrator
 * @since 2019/05/23
 *
 */
public abstract class FlyWeight {
    protected String charStr = "";
    protected int fontSize;
    protected abstract void operator(int fontSize);
    // 显示方法
    protected abstract void displayCharator();
}

享元工厂类:

package com.ssy.wlj.flyweight;

import java.util.Hashtable;

/**
 * CharactorFactory 工厂
 * 
 * @author Administrator
 * @since 2019/05/23
 *
 */
public class CharactorFactory {
    private Hashtable<String, FlyWeight> charactors = new Hashtable<String, FlyWeight>();

    // 构造函数
    public CharactorFactory() {
        charactors.put("A", new FlyWeightAIml());
        charactors.put("B", new FlyWeightBIml());
    }

    // 获得指定字符实例
    public FlyWeight getCharactor(String key) {
        FlyWeight charactor = (FlyWeight) charactors.get(key);
        if (charactor == null) {
            if (key.equals("A")) {
                charactor = new FlyWeightAIml();
            } else if (key.equals("B")) {
                charactor = new FlyWeightBIml();
            }
            charactors.put(key, charactor);
        }
        return charactor;
    }
}

具体实现类:

package com.ssy.wlj.flyweight;

public class FlyWeightAIml extends FlyWeight {
    
    public FlyWeightAIml() {
        this.charStr = "A";
        this.fontSize=12;
    }

    @Override
    protected void operator(int fontSize) {
        this.fontSize=fontSize;

    }

    @Override
    protected void displayCharator() {
        System.out.println("字符:" + this.charStr + ",大小:" + fontSize);
    }

}

 

package com.ssy.wlj.flyweight;

public class FlyWeightBIml extends FlyWeight {
    
    public FlyWeightBIml() {
        this.charStr = "B";
        this.fontSize = 12;
    }

    @Override
    protected void operator(int fontSize) {
        this.fontSize = fontSize;
    }

    @Override
    protected void displayCharator() {
        System.out.println("字符:" + this.charStr + ",大小:" + fontSize);
    }

}

最后编写测试类:

package com.ssy.wlj.flyweight;

public class Client {
    public static void main(String[] args) {
        //flyweith();
        flyweith2();
    }

    // 设置字符的大小
    public static void display(FlyWeight objChar, int nSize) {
        try {
            System.out.println("字符:" + objChar.charStr + ",大小:" + nSize);
        } catch (Exception err) {
        }
    }
    
    public static void flyweith() {
        FlyWeightAIml a = new FlyWeightAIml();
        FlyWeightBIml b = new FlyWeightBIml();
        // 显示字符A
        display(a, 12);
        // 显示字符B
        display(b, 14);
    }
    
    public static void flyweith2() {
        FlyWeightAIml a = new FlyWeightAIml();
        FlyWeightBIml b = new FlyWeightBIml();
        // 设置字符A的大小
        a.operator(12);
        // 显示字符B
        a.displayCharator();
        // 设置字符B的大小
        b.operator(14);
        // 显示字符B
        b.displayCharator();
    }
}

运行效果:

字符:A,大小:12
字符:B,大小:14

 三、享元模式实例展示

我们将创建一个 Shape 接口和实现了 Shape 接口的实体类 Circle。下一步是定义工厂类 ShapeFactory。
ShapeFactory 有一个 Circle 的 HashMap,其中键名为 Circle 对象的颜色。无论何时接收到请求,都会创建一个特定颜色的圆。ShapeFactory 检查它的 HashMap 中的 circle 对象,如果找到 Circle 对象,则返回该对象,否则将创建一个存储在 hashmap 中以备后续使用的新对象,并把该对象返回到客户端。
FlyWeightPatternDemo,我们的演示类使用 ShapeFactory 来获取 Shape 对象。它将向 ShapeFactory 传递信息(red / green / blue/ black / white),以便获取它所需对象的颜色。

类图如下:

步骤 1
创建一个接口。

package com.ssy.wlj.flyweight2;

/**
 *   享元接口
 * @author Administrator
 * @since 2019/05/23
 *
 */
public interface Shape {
    void draw();
}

步骤 2

创建实现接口的实体类。

package com.ssy.wlj.flyweight2;

public class Circle implements Shape {
    private String color;
    private int x;
    private int y;
    private int radius;

    public Circle(String color) {
        this.color = color;
    }

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }

    public void setRadius(int radius) {
        this.radius = radius;
    }

    @Override
    public void draw() {
        System.out.println("Circle: Draw() [Color : " + color + ", x : " + x + ", y :" + y + ", radius :" + radius);
    }
}

步骤 3

创建一个工厂,生成基于给定信息的实体类的对象。

package com.ssy.wlj.flyweight2;

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;
    }
}

步骤 4

使用该工厂,通过传递颜色信息来获取实体类的对象。

package com.ssy.wlj.flyweight2;

public class Client {
    private static final String colors[] = { "Red", "Green", "Blue", "White", "Black" };

    public static void main(String[] args) {

        for (int i = 0; i < 20; ++i) {
            Circle circle = (Circle) ShapeFactory.getCircle(getRandomColor());
            circle.setX(getRandomX());
            circle.setY(getRandomY());
            circle.setRadius(100);
            circle.draw();
        }
    }

    private static String getRandomColor() {
        return colors[(int) (Math.random() * colors.length)];
    }

    private static int getRandomX() {
        return (int) (Math.random() * 100);
    }

    private static int getRandomY() {
        return (int) (Math.random() * 100);
    }
}

步骤 5

执行程序,输出结果:

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
Creating circle of color : Blue
Circle: Draw() [Color : Blue, x : 13, y :4, radius :100
Circle: Draw() [Color : Green, x : 21, y :21, radius :100
Circle: Draw() [Color : Blue, x : 55, y :86, radius :100
Circle: Draw() [Color : White, x : 90, y :70, radius :100
Circle: Draw() [Color : Green, x : 78, y :3, radius :100
Circle: Draw() [Color : Green, x : 64, y :89, radius :100
Circle: Draw() [Color : Blue, x : 3, y :91, radius :100
Circle: Draw() [Color : Blue, x : 62, y :82, radius :100
Circle: Draw() [Color : Green, x : 97, y :61, radius :100
Circle: Draw() [Color : Green, x : 86, y :12, radius :100
Circle: Draw() [Color : Green, x : 38, y :93, radius :100
Circle: Draw() [Color : Red, x : 76, y :82, radius :100
Circle: Draw() [Color : Blue, x : 95, y :82, radius :100

 

posted on 2019-05-23 16:02  happy_2010  阅读(96)  评论(0编辑  收藏  举报