2

现在我正在研究 Flyweight 设计模式。我试图通过谷歌找到一些例子,这就是我发现的。

import java.awt.Color;
import java.awt.Graphics;

public interface Shape {

    public void draw(Graphics g, int x, int y, int width, int height, Color color);
}

这是界面形状。

import java.awt.Color;
import java.awt.Graphics;

public class Line implements Shape {...}
public class Oval implements Shape {...}

这两个类实现了 Shape 接口。

import java.util.HashMap;

public class ShapeFactory {

    private static final HashMap<ShapeType, Shape> shapes = new HashMap<ShapeType, Shape>();

    public static Shape getShape(ShapeType type) {
        Shape shapeImpl = shapes.get(type);

        if (shapeImpl == null) {
            if (type.equals(ShapeType.OVAL_FILL)) {
                shapeImpl = new Oval(true);
            } else if (type.equals(ShapeType.OVAL_NOFILL)) {
                shapeImpl = new Oval(false);
            } else if (type.equals(ShapeType.LINE)) {
                shapeImpl = new Line();
            }
            shapes.put(type, shapeImpl);
        }
        return shapeImpl;
    }
    
    public static enum ShapeType {
        OVAL_FILL, OVAL_NOFILL, LINE;
    }
}

通过这个 Factory 类,Oval 或 Line 类是由类型制成的。我理解,但我有一个问题。我了解到静态字段或函数只能在静态类中使用。 但是,在这个例子中,静态 Hashmap 和函数是在非静态类 ShapeFactory 中声明的。我在 google 中找到了其他示例,但每个示例都与此类似。我试图做我自己的享元模型,但它不起作用。任何人都可以解释一下吗?

4

2 回答 2

3
于 2021-10-07T00:13:08.570 回答
1

正如他们上面提到的,您提供的示例不是享元模式。此模式有助于减少应用程序使用的内存量。在以下示例中,我们有一个包含歌曲和播放列表的音乐应用程序。

每首歌曲都有一个 ID、歌曲名称和大小。

public class Song {
    Long id;
    String name;
    byte[] audioSize;

    public Song(Long id, String name) {
        this.id = id;
        this.name = name;
        audioSize = new byte[1000000];
    }
}

播放列表包含歌曲列表和播放列表名称。

public class PlayList {

    private List<Song> songs;
    private String name;

    public PlayList(String name) {
        this.songs = new ArrayList<>();
        this.name = name;
    }

    public void addSong(Song song){
        this.songs.add(song);
    }
}

为了查看应用程序的行为,我创建了一个包含 1000 首歌曲和 300000 个播放列表的 Main 类,每个播放列表包含 80 首歌曲。应用程序启动时会提示可用内存,结束前会提示已用内存。如果您运行此代码,它将由于内存限制而崩溃。

import java.util.*;

public class Main {

    private static final String[] songNames = new String[1000];
    private static final String[] playListNames = new String[300000];
    private static final List<PlayList> playLists = new ArrayList<>();

    public static void main(String[] args) {

        Runtime runtime = Runtime.getRuntime();
        System.out.println("Available memory: " + (runtime.maxMemory() / 1024 / 1024));

        initArrays();
        createRandomPlayLists();
        System.out.println("Created playlists: " + playLists.size());

        long usedMemory = runtime.totalMemory() - runtime.freeMemory();
        System.out.println("Used memory : " + usedMemory / 1024 / 1024);
    }

    private static void createRandomPlayLists() {
        Random random = new Random();
        long id = 0L;
        for (int i = 0; i < playListNames.length; i++) {
            PlayList playList = new PlayList(playListNames[i]);
            for (int j = 0; j < 80; j++) {
                Song song = new Song(++id, songNames[random.nextInt(songNames.length)]);
                playList.addSong(song);
            }
            playLists.add(playList);
        }
    }

    private static void initArrays() {
        for (int i = 0; i < songNames.length; i++) {
            songNames[i] = "Song " + i;
        }
        for (int i = 0; i < playListNames.length; i++) {
            playListNames[i] = "PlayList " + i;
        }
    }
}

为了避免这种内存限制,我们可以使用飞行重量模式。为了实现这个模式,我们可以添加一个 Map 来存储添加到播放列表中的歌曲。如果一首歌曲从未添加到播放列表中,它将被添加到地图中。在执行结束时,应用程序使用的总内存应该在 2.6 GB 左右

import java.util.*;

public class Main {

    private static final String[] songNames = new String[1000];
    private static final String[] playListNames = new String[300000];
    private static final List<PlayList> playLists = new ArrayList<>();

    public static void main(String[] args) {

        Runtime runtime = Runtime.getRuntime();
        System.out.println("Available memory: " + (runtime.maxMemory() / 1024 / 1024));

        initArrays();
        createRandomPlayLists();
        System.out.println("Created playlists: " + playLists.size());

        long usedMemory = runtime.totalMemory() - runtime.freeMemory();
        System.out.println("Used memory : " + usedMemory / 1024 / 1024);
    }

    private static void createRandomPlayLists() {
        Random random = new Random();
        long id = 0L;
        Map<String, Song> loadedSongs = new HashMap<>();
        for (int i = 0; i < playListNames.length; i++) {
            PlayList playList = new PlayList(playListNames[i]);
            for (int j = 0; j < 80; j++) {

                String songName = songNames[random.nextInt(songNames.length)];
                if (loadedSongs.containsKey(songName)) {
                    playList.addSong(loadedSongs.get(songName));
                } else {
                    //Create the song in memory
                    Song song = new Song(++id, songName);
                    //Add the song to the map. This will make the song available the next time it is needed
                    loadedSongs.put(songName, song);
                    playList.addSong(song);
                }
            }
            playLists.add(playList);
        }
    }

    private static void initArrays() {
        for (int i = 0; i < songNames.length; i++) {
            songNames[i] = "Song " + i;
        }
        for (int i = 0; i < playListNames.length; i++) {
            playListNames[i] = "PlayList " + i;
        }
    }
}

我将使用 SongFactory 类添加一个实现,该类将允许使用布尔值启用或禁用享元功能


import java.util.HashMap;
import java.util.Map;

public class SongFactory {

    private static final Map<String, Song> loadedSongs = new HashMap<>();
    public static boolean flyweightEnabled = true;
    private static Long id = 0L;

    public static Song newSong(String songName) {
        if (flyweightEnabled) {
            //If the song is in memory, we return it
            if (loadedSongs.containsKey(songName)) {
                return loadedSongs.get(songName);
            } else {
                //Create the song in memory
                Song song = new Song(++id, songName);
                //Add the song to the map. This will make the song available the next time it is needed
                loadedSongs.put(songName, song);
                return song;
            }
        } else {
            Song song = new Song(++id, songName);
            return song;
        }
    }
}

import java.util.*;

public class Main {

    private static final String[] songNames = new String[1000];
    private static final String[] playListNames = new String[300000];
    private static final List<PlayList> playLists = new ArrayList<>();

    public static void main(String[] args) {

        Runtime runtime = Runtime.getRuntime();
        System.out.println("Available memory: " + (runtime.maxMemory() / 1024 / 1024));

        initArrays();
        createRandomPlayLists();
        System.out.println("Created playlists: " + playLists.size());

        long usedMemory = runtime.totalMemory() - runtime.freeMemory();
        System.out.println("Used memory : " + usedMemory / 1024 / 1024);
    }

    private static void createRandomPlayLists() {
        Random random = new Random();
        for (int i = 0; i < playListNames.length; i++) {
            PlayList playList = new PlayList(playListNames[i]);
            for (int j = 0; j < 80; j++) {
                Song song = SongFactory.newSong(songNames[random.nextInt(songNames.length)]);
                playList.addSong(song);
            }
            playLists.add(playList);
        }
    }

    private static void initArrays() {
        for (int i = 0; i < songNames.length; i++) {
            songNames[i] = "Song " + i;
        }
        for (int i = 0; i < playListNames.length; i++) {
            playListNames[i] = "PlayList " + i;
        }
    }
}

我希望这将帮助您更好地理解 Flyweight 模式

于 2021-10-06T22:54:23.590 回答