• 设计模式15——享元模式


    写文章的初心主要是用来帮助自己快速的回忆这个模式该怎么用,主要是下面的UML图可以起到大作用,在你学习过一遍以后可能会遗忘,忘记了不要紧,只要看一眼UML图就能想起来了。同时也请大家多多指教。

    享元模式(Flyweight)

    是一种结构型模式

    目录

    一、概述

    1.1、先给出通用的UML图:

    二、举例

    2.1、简单举例认识此模式:

    2.2、举例:


    一、概述

    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实现代码如下:

    网站抽象类:

    1. abstract class WebSite {
    2. public abstract void use(User user);
    3. }

    具体网站:

    1. public class ConcreteWebSite extends WebSite {
    2. private String webName;
    3. public ConcreteWebSite(String webName) {
    4. this.webName = webName;
    5. }
    6. @Override
    7. public void use(User user) {
    8. System.out.println("网站名:" + this.webName + ",用户名:" + user.getUserName());
    9. }
    10. }

    网站控制工厂:

    1. public class WebSiteFactory {
    2. private HashMap hashMap = new HashMap<>();
    3. public WebSite getWebSiteCategory(String key) {
    4. if (!hashMap.containsKey(key)) {
    5. hashMap.put(key, new ConcreteWebSite(key));
    6. }
    7. return hashMap.get(key);
    8. }
    9. public int getWebSiteCount() {
    10. return hashMap.size();
    11. }
    12. }

    用户:

    1. public class User {
    2. private String userName;
    3. public User(String userName) {
    4. this.userName = userName;
    5. }
    6. public String getUserName() {
    7. return userName;
    8. }
    9. }

     主程序(发起请求的类):

    1. public class Main {
    2. public static void main(String[] args) {
    3. WebSiteFactory webSiteFactory = new WebSiteFactory();
    4. WebSite webSite1 = webSiteFactory.getWebSiteCategory("淘宝");
    5. webSite1.use(new User("张三"));
    6. WebSite webSite2 = webSiteFactory.getWebSiteCategory("淘宝");
    7. webSite2.use(new User("李四"));
    8. WebSite webSite3 = webSiteFactory.getWebSiteCategory("博客");
    9. webSite3.use(new User("王五"));
    10. WebSite webSite4 = webSiteFactory.getWebSiteCategory("博客");
    11. webSite4.use(new User("老刘"));
    12. System.out.println("网站总数为:" + webSiteFactory.getWebSiteCount());
    13. }
    14. }

    这里就不再举例了,可以把上面的Java例子复制到你本地,运行main函数试一下加深理解。这些代码都是我自己学习的时候根据一些教材手敲的,不存在bug可以直接运行。

    如果觉得本文还不错,就请点个赞吧!如果有建议,也请评论指教和讨论!

  • 相关阅读:
    Unity 3D 调整cube的颜色
    PyCharm 手动下载插件
    剑指 Offer 12. 矩阵中的路径
    【UniApp】-uni-app-OptionAPI应用生命周期和页面生命周期
    查看docker容器中的ip
    在PHP8中使用instanceof操作符检测对象类型-PHP8知识详解
    STM32 入门教程(江科大教材)#笔记2
    WordPress(6)网站侧边栏倒计时进度小工具
    回溯 Leetcode 332 重新安排行程
    OC-KVO和KVC
  • 原文地址:https://blog.csdn.net/weixin_43687024/article/details/139189468