您现在的位置是:首页 >学无止境 >设计模式 -第1部分 避免浪费- 第1章 Flyweight 模式 - 共享对象避免浪费网站首页学无止境

设计模式 -第1部分 避免浪费- 第1章 Flyweight 模式 - 共享对象避免浪费

是佩奇吗? 2024-06-26 06:01:03
简介设计模式 -第1部分 避免浪费- 第1章 Flyweight 模式 - 共享对象避免浪费

第1部分 避免浪费

注:其内容主要来自于【日】-结城浩 著《图解设计模式》20章节 极力推荐大家阅读原著

第1章 Flyweight 模式 - 共享对象避免浪费

image-20230525135640753

1.1 Flyweight 模式

Flyweight 的意思"轻量级",其在英文中的原意指比赛中选手体重最轻等级的一种描述。所以顾名思义,该模式的主要作用就是为了让对象变得更"轻"。

那么这里的"轻"又如何理解呢?

在计算机的应用体系当中,所有的一切应用层的东西都是虚拟的,而这些虚拟的构建都存储在内存当中。所以这里的"轻"代指的就是一个对象所占内存的空间大小。占用空间的比率越大则越"重",反之则"轻"。

举个例子,比如说我们在 Java 当中需要创建一个对象,该对象的本身生成的中间过程比较复杂,也使得该对象比较庞大,内存分配给该对象的占用比也就响应的比距大。当程序在执行过程当中,如果大量的需要使用到该对象,先不谈,该对象每次一的 new 关键字所带来的资源上的负荷,就其该对象如果都使用 new 关键字来进行分配,将会消耗大量的内存空间。

所以关于 Flyweight 模式,其实最终的目的就是为了“尽量的通过共享实例取代 new 实例”。

相当于我们有一个共享池,在共享池中只存在唯一不同实例,公用已经存在的实例。这就是 Flyweight 模式的核心重点。

1.2 实例程序

这里先使用 Flyweight 模式设计一个简单的示例程序。

其具体的程序目的就是将其下 代码清单中 20-1 ~ 20-9 中的许多普通文本组合成一个 “大型字符”的类,而这些普通字符的实例就是重复的实例。

而下面的代码清单中的各个以 bigx.txt 命名的文件,是为了方便进行测试,而通过文本的格式将单个普通字符存储到本地文件当中,在拼接"大型字符"的时候,将其需要的文件内容加载读取到内存当中。

image-20230525140625980

image-20230525140649139

image-20230525140704274

关于类的构建说明如表 20-1 下图所示

这里我用其他字符格式代替需要的可复制或该网站生成 BootSchool

代码清单 1.1 BootSchool banner图

 __      _______    ______    
/      / ___   )  / ___     
/) )   /   )  |  /       
  | |       /   )     ___) /  
  | |     _/   /     (___ (   
  | |    /   _/          )   
__) (_  (   (__/  /\___/  /  
\____/  \_______/  \______/    
    ___      _______     ______ 
   /   )    (  ____    / ____ 
  / /) |    | (    /  ( (    /
 / (_) (_   | (____    | (____  
(____   _)  (_____    |  ___  
     ) (          ) )  | (   ) )
     | |    /\____) )  ( (___) )
     (_)    \______/    \_____/ 
 ______      _____      _____
/ ___      / ___     / ___ 
/   )  )  ( (___) )  ( (   ) )
    /  /         /   ( (___) |
   /  /     / ___     \____  |
  /  /     ( (   ) )        ) |
 /  /      ( (___) )  /\____) )
 \_/        \_____/   \______/

image-20230525140739332

BigChar 表示 “大型字符” 的类,该类的主要作用就是通过文件流的形式将其上述代码清单 20-8 中提到的内容读取到内存当中,然后通过 print 方法打印输出大型字符。而这些大型字符,在创建的过程当中会消耗大量的计算机内存资源,因此我们考虑的重点是在于,如何通过共享的形式,将这些唯一的 BigChar 实例作为其共享资源。

BigCharFactory 工厂的作用就是,会更具其具体的需要从而生成指定而 BigChar 实例,但是在其生成之前首先会进行相应的具体判断,如果其发现之前已经生成过该唯一的 BigChar 实例,则直接使用即可,否则生成新的唯一实例。而对于生成的实例,我们将其存储在 java.util.HashMap 类定义的 pool 字段当中,进行维护。

BigString 类的作用就是将其 BgiChar “大型字符” 组合成指定“大型字符串” 。

Main 类用于最终测试程序行为的类。

实例程序 UML 类图

image-20230525144022968

代码清单 1.1 BigChar 类 (BigChar.java)

package com.peggy.flyweight.example01;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

/**
 * @Projectname: designPatterns
 * @Filename: BigChar
 * @Author: peggy
 * @Data:2023/5/25 11:14
 * @Description: 根据字符生成字符串
 */

public class BigChar {

    //字符名字
    private char charname;

    //大型字符对应的字符串
    private String fontdata;

    //字符串文件路径
    private static String PATH = "E:\workspaces\java\designPatterns\peggy-flyweight-pattren-01\src\main\resources\";

    public BigChar(char charname) {
        this.charname = charname;
        try {
            BufferedReader reader = new BufferedReader(
                    new FileReader(PATH + "big" + charname + ".txt"));
            String line;
            StringBuilder buf = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                //写入到内存
                buf.append(line);
                buf.append("
");
            }
            this.fontdata = buf.toString();

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public void print() {
        System.out.println(fontdata);
    }
}

代码清单 1.1 BigCharFactory类 (BigCharFactory.class)

  • !标注[1] 处 BigCharFactory 声明成静态单利模式,是为了保证全局只有一个静态工厂 BigCharFactory 实例。试想如果全局中为私有化其构造方法,就可以创建多个工厂实例,其每个工厂实例都会有一个 pool ,也就失去了 Flyweight 模式存在的意义。
  • !标注[2] 处对于 getBigchar 方法用其 synchronized 关键字进行修饰,其目的也是为了保证 pool 的对象不会重复创建。值得注意的是,虽然无论是否在并发情况下, pool 中的实例受 Map 集合的 Key / Value 键值对的约束,都是有且只有一个唯一的不同实例存在。但是这并不影响在并发情况下出现,BigChar 实例重复创建的可能性存在。所以这里使用 synchronized 关键字修饰是显得尤为重要的。
package com.peggy.flyweight.example01;

import java.util.HashMap;
import java.util.Map;

/**
 * @Projectname: designPatterns
 * @Filename: BigCharFactory
 * @Author: peggy
 * @Data:2023/5/25 14:48
 * @Description: 生成  BigChar 实例的工厂 实现其共享功能
 */

public class BigCharFactory {

    //管理已经生成的 BigChar 实例
    private Map<String, BigChar> pool = new HashMap<>();
    //单利模式,其保证只有一个工厂对象
    /*!标注[1]*/
    private static BigCharFactory singleton = new BigCharFactory();

    private BigCharFactory() {
    }

    public static BigCharFactory getSingleton() {
       return singleton;
    }

    //生成共享 BigChar 唯一对象
    /*!标注[2]*/
    public synchronized  BigChar getBigChar(char charname) {
        BigChar bc = pool.get(String.valueOf(charname));
        if (bc == null) {
            bc = new BigChar(charname);
            pool.put(String.valueOf(charname), bc);
        }
        return bc;
    }
}

代码清单 1.1 BigString类 (BigString.class)

package com.peggy.flyweight.example01;

/**
 * @Projectname: designPatterns
 * @Filename: BigString
 * @Author: peggy
 * @Data:2023/5/25 15:15
 * @Description: 大型字符串创建类
 */

public class BigString {
    //"大型字符" 的数组
    private BigChar[] bigChars;

    //构造函数
    public BigString(String string) {
        bigChars = new BigChar[string.length()];
        BigCharFactory factory = BigCharFactory.getSingleton();
        for (int i = 0; i < bigChars.length; i++) {
            bigChars[i] = factory.getBigChar(string.charAt(i));
        }
    }

    //打印显示
    public void print() {
        for (int i = 0; i < bigChars.length; i++) {
            bigChars[i].print();
        }
    }
}

image-20230525152457323

Main 类

package com.peggy.flyweight.example01;

/**
 * @Projectname: designPatterns
 * @Filename: Main
 * @Author: peggy
 * @Data:2023/5/25 15:25
 * @Description: 案例测试类
 */

public class Main {
    public static void main(String[] args) {
        BigString bs = new BigString("15569732xxx");
        bs.print();
    }
}
image-20230525154918578
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。