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