1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
| /**
* 享元接口 - 图标
*/
public interface Icon {
void display(int x, int y, int size);
String getIconName();
byte[] getIconData(); // 模拟图标数据
}
/**
* 具体享元 - 具体图标
*/
public class ConcreteIcon implements Icon {
private final String iconName; // 内部状态 - 图标名称
private final String iconPath; // 内部状态 - 图标路径
private final byte[] iconData; // 内部状态 - 图标数据
public ConcreteIcon(String iconName, String iconPath) {
this.iconName = iconName;
this.iconPath = iconPath;
this.iconData = loadIconData(iconPath); // 模拟加载图标数据
System.out.println("🎨 加载图标: " + iconName + " 从 " + iconPath);
}
private byte[] loadIconData(String path) {
// 模拟从文件系统或网络加载图标数据
try {
Thread.sleep(10); // 模拟IO延迟
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// 生成模拟的图标数据
return new byte[1024]; // 假设每个图标1KB
}
@Override
public void display(int x, int y, int size) {
System.out.println("显示图标 '" + iconName + "' 在位置(" + x + "," + y + ") 大小:" + size + "px");
}
@Override
public String getIconName() {
return iconName;
}
@Override
public byte[] getIconData() {
return iconData.clone(); // 返回副本,保护内部数据
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
ConcreteIcon that = (ConcreteIcon) obj;
return Objects.equals(iconName, that.iconName);
}
@Override
public int hashCode() {
return Objects.hash(iconName);
}
}
/**
* 图标享元工厂
*/
public class IconFactory {
private static final Map<String, Icon> iconCache = new ConcurrentHashMap<>();
private static final AtomicInteger loadCount = new AtomicInteger(0);
private static final AtomicInteger hitCount = new AtomicInteger(0);
// 预定义的图标路径
private static final Map<String, String> iconPaths = new HashMap<>();
static {
iconPaths.put("home", "/icons/home.png");
iconPaths.put("user", "/icons/user.png");
iconPaths.put("settings", "/icons/settings.png");
iconPaths.put("search", "/icons/search.png");
iconPaths.put("logout", "/icons/logout.png");
iconPaths.put("menu", "/icons/menu.png");
iconPaths.put("notification", "/icons/notification.png");
iconPaths.put("download", "/icons/download.png");
iconPaths.put("upload", "/icons/upload.png");
iconPaths.put("delete", "/icons/delete.png");
iconPaths.put("edit", "/icons/edit.png");
iconPaths.put("save", "/icons/save.png");
}
public static Icon getIcon(String iconName) {
Icon icon = iconCache.get(iconName);
if (icon == null) {
String iconPath = iconPaths.get(iconName);
if (iconPath == null) {
throw new IllegalArgumentException("未知的图标: " + iconName);
}
icon = new ConcreteIcon(iconName, iconPath);
iconCache.put(iconName, icon);
loadCount.incrementAndGet();
} else {
hitCount.incrementAndGet();
System.out.println("📋 从缓存获取图标: " + iconName);
}
return icon;
}
public static void printStatistics() {
System.out.println("=== 图标工厂统计 ===");
System.out.println("缓存大小: " + iconCache.size());
System.out.println("加载次数: " + loadCount.get());
System.out.println("缓存命中: " + hitCount.get());
if (loadCount.get() + hitCount.get() > 0) {
double hitRate = (double) hitCount.get() / (loadCount.get() + hitCount.get()) * 100;
System.out.println("命中率: " + String.format("%.1f", hitRate) + "%");
}
System.out.println("缓存图标: " + iconCache.keySet());
}
public static void clearCache() {
iconCache.clear();
loadCount.set(0);
hitCount.set(0);
System.out.println("图标缓存已清空");
}
public static int getCacheSize() {
return iconCache.size();
}
public static long estimateMemoryUsage() {
// 估算内存使用(每个图标约1KB + 对象开销)
return iconCache.size() * 1100L; // 1KB数据 + 100字节对象开销
}
}
/**
* UI元素 - 包含外部状态
*/
public class UIElement {
private Icon icon; // 享元对象
private int x, y; // 外部状态 - 位置
private int size; // 外部状态 - 大小
private String tooltip; // 外部状态 - 提示文本
private boolean visible; // 外部状态 - 可见性
private String elementId; // 外部状态 - 元素ID
public UIElement(String iconName, int x, int y, int size, String tooltip, String elementId) {
this.icon = IconFactory.getIcon(iconName);
this.x = x;
this.y = y;
this.size = size;
this.tooltip = tooltip;
this.elementId = elementId;
this.visible = true;
}
public void render() {
if (visible) {
icon.display(x, y, size);
System.out.println(" ID: " + elementId + ", 提示: " + tooltip);
}
}
public void moveTo(int newX, int newY) {
this.x = newX;
this.y = newY;
}
public void resize(int newSize) {
this.size = newSize;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
public void setTooltip(String tooltip) {
this.tooltip = tooltip;
}
public String getIconName() {
return icon.getIconName();
}
@Override
public String toString() {
return "UIElement{" +
"icon=" + icon.getIconName() +
", position=(" + x + "," + y + ")" +
", size=" + size +
", tooltip='" + tooltip + "'" +
", visible=" + visible +
", id='" + elementId + "'" +
'}';
}
}
/**
* 网页 - 包含多个UI元素
*/
public class WebPage {
private List<UIElement> elements;
private String pageTitle;
public WebPage(String pageTitle) {
this.pageTitle = pageTitle;
this.elements = new ArrayList<>();
}
public void addElement(String iconName, int x, int y, int size, String tooltip, String elementId) {
UIElement element = new UIElement(iconName, x, y, size, tooltip, elementId);
elements.add(element);
}
public void render() {
System.out.println("=== 渲染页面: " + pageTitle + " ===");
for (UIElement element : elements) {
element.render();
}
}
public void createNavigationBar() {
System.out.println("🧭 创建导航栏");
addElement("home", 10, 10, 24, "首页", "nav-home");
addElement("user", 50, 10, 24, "用户中心", "nav-user");
addElement("settings", 90, 10, 24, "设置", "nav-settings");
addElement("search", 130, 10, 24, "搜索", "nav-search");
addElement("logout", 170, 10, 24, "退出", "nav-logout");
}
public void createSidebar() {
System.out.println("📋 创建侧边栏");
addElement("menu", 10, 60, 20, "菜单", "sidebar-menu");
addElement("notification", 10, 90, 20, "通知", "sidebar-notification");
addElement("download", 10, 120, 20, "下载", "sidebar-download");
addElement("upload", 10, 150, 20, "上传", "sidebar-upload");
}
public void createToolbar() {
System.out.println("🔧 创建工具栏");
addElement("save", 250, 60, 18, "保存", "toolbar-save");
addElement("edit", 280, 60, 18, "编辑", "toolbar-edit");
addElement("delete", 310, 60, 18, "删除", "toolbar-delete");
}
public void updateElement(String elementId, int newX, int newY) {
for (UIElement element : elements) {
if (element.toString().contains(elementId)) {
element.moveTo(newX, newY);
System.out.println("移动元素 " + elementId + " 到位置(" + newX + "," + newY + ")");
break;
}
}
}
public void printStatistics() {
Map<String, Integer> iconCounts = new HashMap<>();
for (UIElement element : elements) {
String iconName = element.getIconName();
iconCounts.put(iconName, iconCounts.getOrDefault(iconName, 0) + 1);
}
System.out.println("=== 页面统计: " + pageTitle + " ===");
System.out.println("UI元素总数: " + elements.size());
System.out.println("图标使用统计:");
for (Map.Entry<String, Integer> entry : iconCounts.entrySet()) {
System.out.println(" " + entry.getKey() + ": " + entry.getValue() + " 次");
}
}
public int getElementCount() {
return elements.size();
}
}
/**
* 网站 - 管理多个页面
*/
public class Website {
private List<WebPage> pages;
private String siteName;
public Website(String siteName) {
this.siteName = siteName;
this.pages = new ArrayList<>();
}
public WebPage createPage(String pageTitle) {
WebPage page = new WebPage(pageTitle);
pages.add(page);
return page;
}
public void renderAllPages() {
System.out.println("🌐 === 渲染整个网站: " + siteName + " ===");
for (WebPage page : pages) {
page.render();
System.out.println();
}
}
public void printOverallStatistics() {
int totalElements = 0;
for (WebPage page : pages) {
totalElements += page.getElementCount();
}
System.out.println("=== 网站整体统计: " + siteName + " ===");
System.out.println("页面总数: " + pages.size());
System.out.println("UI元素总数: " + totalElements);
System.out.println("估算内存使用: " + IconFactory.estimateMemoryUsage() + " 字节");
if (totalElements > 0) {
double memoryPerElement = (double) IconFactory.estimateMemoryUsage() / totalElements;
System.out.println("平均每元素内存: " + String.format("%.1f", memoryPerElement) + " 字节");
}
}
}
// 网页图标缓存演示
public class WebPageIconFlyweightDemo {
public static void main(String[] args) {
System.out.println("=== 网页图标缓存享元模式演示 ===");
Website corporateWebsite = new Website("企业官网");
System.out.println("\n=== 创建首页 ===");
WebPage homePage = corporateWebsite.createPage("首页");
homePage.createNavigationBar();
homePage.createSidebar();
System.out.println("\n=== 创建用户页面 ===");
WebPage userPage = corporateWebsite.createPage("用户中心");
userPage.createNavigationBar(); // 复用导航栏图标
userPage.createToolbar();
System.out.println("\n=== 创建设置页面 ===");
WebPage settingsPage = corporateWebsite.createPage("系统设置");
settingsPage.createNavigationBar(); // 再次复用导航栏图标
settingsPage.createSidebar(); // 复用侧边栏图标
settingsPage.createToolbar(); // 复用工具栏图标
System.out.println("\n=== 图标工厂统计 ===");
IconFactory.printStatistics();
System.out.println("\n=== 各页面统计 ===");
homePage.printStatistics();
userPage.printStatistics();
settingsPage.printStatistics();
System.out.println("\n=== 渲染所有页面 ===");
corporateWebsite.renderAllPages();
System.out.println("\n=== 网站整体统计 ===");
corporateWebsite.printOverallStatistics();
System.out.println("\n=== 享元模式效果分析 ===");
int totalUIElements = homePage.getElementCount() + userPage.getElementCount() + settingsPage.getElementCount();
int uniqueIcons = IconFactory.getCacheSize();
System.out.println("UI元素总数: " + totalUIElements);
System.out.println("唯一图标数: " + uniqueIcons);
System.out.println("复用比例: " + String.format("%.1f",
((double)(totalUIElements - uniqueIcons) / totalUIElements) * 100) + "%");
System.out.println("\n=== 内存节约分析 ===");
long actualMemory = IconFactory.estimateMemoryUsage();
long wouldBeMemory = totalUIElements * 1100L; // 如果每个元素都有独立图标
long savedMemory = wouldBeMemory - actualMemory;
System.out.println("实际内存使用: " + actualMemory + " 字节");
System.out.println("不使用享元的内存: " + wouldBeMemory + " 字节");
System.out.println("节约内存: " + savedMemory + " 字节");
System.out.println("节约比例: " + String.format("%.1f",
((double)savedMemory / wouldBeMemory) * 100) + "%");
System.out.println("\n=== 动态操作演示 ===");
System.out.println("移动首页的搜索按钮:");
homePage.updateElement("nav-search", 200, 10);
System.out.println("\n添加更多相同类型的元素:");
// 在设置页面添加更多使用现有图标的元素
settingsPage.addElement("save", 50, 200, 16, "保存配置", "config-save");
settingsPage.addElement("user", 80, 200, 16, "用户管理", "user-mgmt");
System.out.println("\n更新后的图标工厂统计:");
IconFactory.printStatistics();
// 清理
IconFactory.clearCache();
}
}
|