51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

Java 设计模式之享元模式(十一)

一、前言 {#一、前言}

本篇主题为结构型模式中的第六个模式--享元模式。上篇 Java 设计模式主题为 《Java 设计模式之外观模式(十)》

二、简单介绍 {#二、简单介绍}

2.1 定义 {#2.1-定义}

享元(Flyweight)模式是构造型模式之一, 它通过与其他类似对象共享数据来减小内存占用。

2.2 参与角色 {#2.2-参与角色}

  1. 抽象享元:所有具体享元类的父类,规定一些需要实现的公共接口,可接收外部状态。

  2. 具体享元:抽象享元角色的具体实现类,并实现了抽象享元角色规定的方法并存储内部状态。

  3. 享元工厂:负责创建和管理享元角色。

2.3 应用场景 {#2.3-应用场景}

  1. 一个应用程序使用了大量的对象。

  2. 由于使用大量的对象,造成很大的存储开销。

  3. 对象的大多数状态都可变为外部状态。

其中,在享元对象内部并不会随环境变化而改变的共享部分,称为内部状态。反之,随环境改变而改变的、不可以共享的状态称为外部状态。

三、实现方式 {#三、实现方式}

以网站为例,小明是个自由职业者,在网上专门帮人完成软件设计(网站后台管理系统)需求。

在不使用享元模式时,通过代码实现上述场景需求:

网站系统:

|---------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 | public class WebSite { private String name; public WebSite(String name) { super(); this.name = name; } public void show() { System.out.println(this.name); } } |

客户端:

|------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class Client { public static void main(String[] args) { WebSite ws1 = new WebSite("A后台管理系统"); WebSite ws2 = new WebSite("B后台管理系统"); ws1.show(); ws2.show(); } } |

打印结果:

|-------------|-------------------------| | 1 2 | A后台管理系统 B后台管理系统 |

从代码上看,当有 N 家公司找小明做后台管理系统时,小明需要编写 N 次代码。假设某一个系统出现 bug,意味着需要维护 N 个系统的代码,维护量很大。因此,上边的代码实现方案不可取。

用过后台管理系统的网友都知道,后台系统的功能大同小异,页面的结构和展示可以相同(内部状态),不同之处在于公司业务需求(外部状态)。

现在,我们使用享元模式实现:

外部状态:

|------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class User { private String name; public User(String name) { super(); this.name = name; } public String getName() { return name; } } |

抽象享元:

|---------------------|----------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 | public abstract class WebSite { // 内部状态 protected String name; public abstract void show(User user); } |

具体享元:

|------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 | class WebSiteA extends WebSite { public WebSiteA(String name) { this.name = name; } @Override public void show(User user) { System.out.println(user.getName() + "的" + this.name); } } |

享元工厂:

|---------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 | public class WebSiteFactory { private static Map<String,WebSite> map = new HashMap<String,WebSite>(); public static WebSite getWebSite(String type) { if (!map.containsKey(type)) { map.put(type, new WebSiteA(type)); } return map.get(type); } } |

客户端:

|---------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class Client { public static void main(String[] args) { WebSite ws1 = WebSiteFactory.getWebSite("后台管理系统"); WebSite ws2 = WebSiteFactory.getWebSite("后台管理系统"); System.out.println(ws1 == ws2); ws1.show(new User("A 公司")); ws2.show(new User("B 公司")); } } |

打印结果:

|---------------|--------------------------------------| | 1 2 3 | true A 公司的后台管理系统 B 公司的后台管理系统 |

从结果可知,两家公司通用一套系统模板,很大的节省了小明的开发量和维护量。

总结:享元模式可以避免大量非常相似的类开销。

UML 类图表示如下:

赞(0)
未经允许不得转载:工具盒子 » Java 设计模式之享元模式(十一)