写文章的初心主要是用来帮助自己快速的回忆这个模式该怎么用,主要是下面的UML图可以起到大作用,在你学习过一遍以后可能会遗忘,忘记了不要紧,只要看一眼UML图就能想起来了。同时也请大家多多指教。
享元模式(Flyweight)
是一种结构型模式。
目录
一、概述
1、运用共享技术有效地支持大量细粒度的对象;
2、享元模式可以避免大量非常相似类的开销。在程序设计中,有时需要生成大量细粒度的类实例来表示数据。如果能发现这些实例除了几个参数外基本上都是相同的,有时就能够大幅度地减少需要实例化的类的数量。如果能把那些参数转移到类实例的外面,在方法调用时将它们传递进来,就可以通过共享大幅度地减少单个实例的数目;
3、如果一个应用程序使用大量的对象,而大量的这些对象造成了很大的存储开销时;
4、内部状态存储在享元对象(目标对象)中,它包含了独立于其他对象的信息,这些信息使得享元对象可以被分享; 5、外部状态取决享元对象(目标对象)的所在场景,根据场景而变化,因为是动态变化的所以不能够共享。但有时会根据需要将外部状态传递给享元对象; 6、对象的大多数状态可以是外部状态,如果可以从对象中删除外部状态,那么可以用相对较少的共享对象取代很多组对象;那么此时可以考虑使用享元模式。
(注1:'粒度'是被用来描述对象大小的。如:我们将 淘宝应用程序 和 购物车功能 看做两个对象,那么我们可以说 淘宝 比起 购物车 粒度要大,或者说 购物车 比起 淘宝 粒度要小)
(注2:享元模式和原型模式都是针对一堆相似类对象。不同的是:享元模式是缩减它们从而减少储存开销;而原型模式是优化它们创建的方式从而减少新增和复制的时间开销。并且两种模式思想完全相反。)
1.1、先给出通用的UML图:
(对模式的简单认识将在下面简单举例认识此模式中说明)
二、举例
2.1、简单举例认识此模式:
**2.1.1、**假设王五和老刘都要访问博客网站,按照以往的思维,那肯定是要实例化两个博客网站的,如下:
**2.1.2、**那我们先进行初步的抽象,将博客对象都分为两部分,个人信息和网站功能:
**2.1.3、**我们可以发现,上述两个博客的实例对象,除了个人信息部分,其他地方都一样,此时我们就可想到享元模式,尝试将个人信息这部分转移出来,也就是将不同的地方拎出来,然后将相同的部分只保留一份:
**2.1.4、**对比上面两张图可以看到,节省了一个功能部分的存储空间。同理要是有10个人,就会有10个个人信息部分,但功能部分还是只有一份。通过这样的设计就达到了节省空间的目的。也就是把变与不变的地方分开来分析与设计。
此外:
- 目标对象(享元对象):博客网站
- 内部状态:功能部分
- 外部状态:个人信息部分
2.2、举例:
**2.2.1、**假设现有四个人,张三、李四、王五、老刘,其中张三和李四要访问淘宝,王五和老刘要访问博客,假设淘宝和博客功能一致,那么相比上面的举例,和上述一样将个人信息部分都拎出来,但要注意新加了个淘宝,我们可以得到:
这次是有两个网站实例淘宝、博客,和四个人的信息部分。再经过分析发现,博客和淘宝可以抽象出:它们都属于网站。这样可以把博客和淘宝当做网站名的外部状态分离出来。
2.2.2、对象之间的关系用UML图表示如下:
(具体的功能部分不是本例的重点,所以就假设淘宝和博客功能部分一样,或者说被抽象出去了)
此例将个人信息单独设计一个类,而淘宝和博客这个就只存储在String字符串中。而实际使用此模式时根据自己的需要可以灵活改变。
2.2.2、Java实现代码如下:
网站抽象类:
java
abstract class WebSite {
public abstract void use(User user);
}
具体网站:
java
public class ConcreteWebSite extends WebSite {
private String webName;
public ConcreteWebSite(String webName) {
this.webName = webName;
}
@Override
public void use(User user) {
System.out.println("网站名:" + this.webName + ",用户名:" + user.getUserName());
}
}
网站控制工厂:
java
public class WebSiteFactory {
private HashMap<String, WebSite> hashMap = new HashMap<>();
public WebSite getWebSiteCategory(String key) {
if (!hashMap.containsKey(key)) {
hashMap.put(key, new ConcreteWebSite(key));
}
return hashMap.get(key);
}
public int getWebSiteCount() {
return hashMap.size();
}
}
用户:
java
public class User {
private String userName;
public User(String userName) {
this.userName = userName;
}
public String getUserName() {
return userName;
}
}
主程序(发起请求的类):
java
public class Main {
public static void main(String[] args) {
WebSiteFactory webSiteFactory = new WebSiteFactory();
WebSite webSite1 = webSiteFactory.getWebSiteCategory("淘宝");
webSite1.use(new User("张三"));
WebSite webSite2 = webSiteFactory.getWebSiteCategory("淘宝");
webSite2.use(new User("李四"));
WebSite webSite3 = webSiteFactory.getWebSiteCategory("博客");
webSite3.use(new User("王五"));
WebSite webSite4 = webSiteFactory.getWebSiteCategory("博客");
webSite4.use(new User("老刘"));
System.out.println("网站总数为:" + webSiteFactory.getWebSiteCount());
}
}
这里就不再举例了,可以把上面的Java例子复制到你本地,运行main函数试一下加深理解。这些代码都是我自己学习的时候根据一些教材手敲的,不存在bug可以直接运行。
如果觉得本文还不错,就请点个赞吧!如果有建议,也请评论指教和讨论!