从零开始学习Java设计模式 | 结构型模式篇:享元模式
Posted 李阿昀
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从零开始学习Java设计模式 | 结构型模式篇:享元模式相关的知识,希望对你有一定的参考价值。
在本讲,我们来学习一下结构型模式里面的最后一个设计模式,即享元模式。
概述
什么是享元模式呢?享元模式是运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似对象的开销,从而提高系统资源的利用率。
知道享元模式的概念之后,我们来看一下现实生活中哪些地方大量的运用到了这种共享思想。大家不妨开动脑筋想一想,共享单车是不是就是啊!在没有共享单车的时候,如果你想骑自行车的话,那么你是不是就得需要自己去购买一辆自行车啊!可能你骑了两天的自行车,热度过了之后,你就不再想去骑它了,这样自行车就会闲置在家里,这本身就是资源的一种浪费。那现在如何去提高资源的一个利用率呢?
共享单车就应运而生了,生产一批自行车,把它们都投放在市面上,如果有人想骑的话,那么他只需要扫码进行一个租赁,然后去骑行即可,骑行完了之后,再进行一个归还,归还的目的就是供其他人进行使用,这就是共享思想,其目的主要就是为了提高资源的利用率。
结构
享元(Flyweight)模式中存在以下两种状态:
- 内部状态(或者内部数据),即不会随着环境的改变而改变的可共享部分。也就是说,不管是我使用还是你使用,内部状态都是一样的。
- 外部状态(或者外部数据),指随环境改变而改变的不可以共享的部分。那么这一部分的数据,我们应该如何进行设置呢?很简单,外部数据可以作为方法的形式参数进行一个传递。
享元模式的实现要领就是区分应用中的这两种状态,并将外部状态外部化。
了解享元模式中存在的两种状态之后,接下来,我们就来看看享元模式里面有哪些角色。
享元模式主要有以下几个角色:
-
抽象享元角色(Flyweight):通常是一个接口或抽象类,在抽象享元类中声明了具体享元类里面公共的方法(现在大家明白,为什么要把该角色定义成接口或者抽象类了吧!其实就是为了进行一个抽取,以便定义成一套规范),这些方法可以向外界提供享元对象的内部数据(内部状态),同时也可以通过这些方法来设置外部数据(外部状态)。
其实,上面我也说到了,外部数据(外部状态)可以作为方法的形式参数进行一个传递,这是因为每个人在使用的时候,外部状态都有可能是不一样的。
-
具体享元(Concrete Flyweight)角色:它实现了抽象享元类,称为享元对象;在具体享元类中为内部状态提供了存储空间,这是因为内部状态是在内部进行一个存储的,并且每个人在使用的时候,内部状态都是一样的。通常我们可以结合单例模式来设计具体享元类,为每一个具体享元类提供唯一的享元对象。
-
非享元(Unsharable Flyweight)角色:并不是所有的抽象享元类的子类都需要被共享,不能被共享的子类可设计为非共享具体享元类;当需要一个非共享具体享元类的对象时,可以直接通过实例化创建,也就是说我们可以直接去创建该类的对象。
注意,该非享元角色我们可以将其理解成外部状态(外部数据),若有多个外部数据的话,则可将它们封装起来。
-
享元工厂(Flyweight Factory)角色:负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,若存在则提供给客户;若不存在的话,则直接创建一个新的享元对象。
享元模式案例
接下来,我们就通过一个案例再来理解一下享元模式以及享元模式里面的两个状态(即内部状态和外部状态),这个案例就是俄罗斯方块。
分析
下面的图片是众所周知的俄罗斯方块中的一个个方块,只要大家有玩过俄罗斯方块,你就一定对它特别特别熟悉。
从上图中可以看到,有I图形、J图形、L图形、O图形、Z图形、T图形以及S图形等这些方块,这些方块就组合成了俄罗斯方块这个游戏。大家在玩俄罗斯方块这个游戏的时候,你会发现图形其实就这几个,只不过是每一个图形可能出现多次,而且颜色也有可能是不一样的,如果我们将每一个小方块都看作是一个实例对象的话,那么I图形出现多次,这就意味着要创建多个对象了。
也就是说,对于相同的图形来说的话,就要创建多个对象了,但这势必会占用过多的内存空间,为了解决这个问题,那么我们就要使用享元模式来进行实现了。这样,对于I图形来说的话,我们只需要去创建一个共享的对象即可,至于不同的颜色,我们可以将其看作是外部状态,这样一来,我们也就能通过参数传递的方式来进行一个实现了。
接下来,我们来看一下下面这张类图,理清楚一下类图涉及到了哪些类以及类和类之间的一个关系。
。。。
实现
。。。
以上是关于从零开始学习Java设计模式 | 结构型模式篇:享元模式的主要内容,如果未能解决你的问题,请参考以下文章