设计模式-享元模式

享元模式是一种有效地支持大量细粒度对象复用的技术,通过共享已有对象减少内存消耗。该模式结合了工厂方法和单例模式的特点,通过享元工厂管理可共享的享元对象。典型应用包括图书馆借书系统和汽车工厂,通过存储共享对象,如书籍和汽车,减少资源占用。

享元模式

享元模式介绍

定义

运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似类的开销,从而提高系统资源的利用率。

优点

  • 如果系统有大量类似的对象,开会节省大量的内存及CPU资源

典型案例

  • StringIntegerLong
  • com.sun.org.apache.bcel.internal.generic.InstructionConstants

享元模式结构与实现

其实享元模式好比 工厂方法模式 和 单例模式 的结合。
使用工厂创建实例,如果实例存在则直接返回不再创建(单例)。对于每个指定享元内容的对象存在唯一实例。

结构

抽象享元角色(Flyweight):是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。
**具体享元(Concrete Flyweight)**角色:实现抽象享元角色中所规定的接口。
非享元(Unsharable Flyweight)角色:是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中。
享元工厂(Flyweight Factory)角色:负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。
在这里插入图片描述

模板实现

import java.util.HashMap;

/**
 * 非享元角色
 */
class UnsharedConcreteFlyweight {
    private String info;
    UnsharedConcreteFlyweight(String info) {
        this.info = info;
    }
    public String getInfo() {
        return info;
    }
    public void setInfo(String info) {
        this.info = info;
    }
}

/**
 * 抽象享元角色
 */
interface Flyweight {
    void operation(UnsharedConcreteFlyweight state);
}

/**
 * 具体享元角色
 */
class ConcreteFlyweight implements Flyweight {
    private String key;
    ConcreteFlyweight(String key) {
        this.key = key;
        System.out.println("具体享元[" + key + "]被创建!");
    }
    @Override
    public void operation(UnsharedConcreteFlyweight outState) {
        System.out.print("具体享元[" + key + "]被调用,");
        System.out.println("非享元信息是:[" + outState.getInfo() + "]");
    }
}
/**
 * 享元工厂角色
 */
class FlyweightFactory {
    private HashMap<String, Flyweight> flyweights = new HashMap<String, Flyweight>();
    public Flyweight getFlyweight(String key) {
        Flyweight flyweight = flyweights.get(key);
        if (flyweight != null) {
            System.out.println("具体享元[" + key + "]已经存在,被成功获取!");
        } else {
            flyweight = new ConcreteFlyweight(key);
            flyweights.put(key, flyweight);
        }
        return flyweight;
    }
}

/**
 * 客户端角色
 */
public class FlyWeightClient {
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();
        Flyweight fa1 = factory.getFlyweight("a");
        Flyweight fa2 = factory.getFlyweight("a");
        Flyweight fa3 = factory.getFlyweight("a");
        Flyweight fb1 = factory.getFlyweight("b");
        Flyweight fb2 = factory.getFlyweight("b");
        Flyweight fb3 = factory.getFlyweight("b");
        fa1.operation(new UnsharedConcreteFlyweight("第1次调用a。"));
        fa2.operation(new UnsharedConcreteFlyweight("第2次调用a。"));
        fa3.operation(new UnsharedConcreteFlyweight("第3次调用a。"));
        fb1.operation(new UnsharedConcreteFlyweight("第1次调用b。"));
        fb2.operation(new UnsharedConcreteFlyweight("第2次调用b。"));
        fb3.operation(new UnsharedConcreteFlyweight("第3次调用b。"));
    }
}

Client运行结果

具体享元[a]被创建!
具体享元[a]已经存在,被成功获取!
具体享元[a]已经存在,被成功获取!
具体享元[b]被创建!
具体享元[b]已经存在,被成功获取!
具体享元[b]已经存在,被成功获取!
具体享元[a]被调用,非享元信息是:[第1次调用a。]
具体享元[a]被调用,非享元信息是:[第2次调用a。]
具体享元[a]被调用,非享元信息是:[第3次调用a。]
具体享元[b]被调用,非享元信息是:[第1次调用b。]
具体享元[b]被调用,非享元信息是:[第2次调用b。]
具体享元[b]被调用,非享元信息是:[第3次调用b。]

示例 图书馆借书

我们只需要存储借用过的书籍信息,无论多少用户借用书籍,书籍的内容都可以通过享元模式存放访问,极大的节省内存空间。

Flyweight: 书籍
Concrete Flyweight: 书籍实现类
Unsharable Flyweight: 借阅者姓名
Flyweight Factory: 图书馆

import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 抽象享元角色:书籍
 */
interface Book {
    /**
     * 借阅书籍
     * @param name 借阅人姓名
     */
    void borrow(String name);
}

/**
 * 具体享元角色:具体书籍
 */
class BookConcrete implements Book{
    private final String bookName;

    BookConcrete(String bookName) {
        System.out.println("创建了书籍:" + bookName);
        this.bookName = bookName;
    }

    @Override
    public void borrow(String name) {
        System.out.println(bookName + "已被[" + name + "]借出");
    }
}

/**
 * 享元工厂角色:图书馆
 */
class Library {
    HashMap<String, Book> books = new HashMap<>();

    public Book getBook(String bookName) {
        Book book = books.get(bookName);
        if (book == null) {
            // 如果书籍不存在则引进这种书到图书馆
            book = new BookConcrete(bookName);
            books.put(bookName, book);
        }
        return book;
    }

    public int getDiffBookNumber() {
        return books.size();
    }

}

public class BookFlyWeightClient {
    public static void main(String[] args) {
        final Library library = new Library();
        library.getBook("鲁滨逊漂流记").borrow("张三");
        library.getBook("鲁滨逊漂流记").borrow("李四");
        library.getBook("鲁滨逊漂流记").borrow("王五");
        library.getBook("西游记").borrow("老六");
        library.getBook("西游记").borrow("张三");
        library.getBook("西游记").borrow("阿七");

        System.out.println(library.getDiffBookNumber());
    }
}

运行结果

创建了书籍:鲁滨逊漂流记
鲁滨逊漂流记已被[张三]借出
鲁滨逊漂流记已被[李四]借出
鲁滨逊漂流记已被[王五]借出
创建了书籍:西游记
西游记已被[老六]借出
西游记已被[张三]借出
西游记已被[阿七]借出
2

示例2 汽车工厂,每种车子最多只造一辆,重复使用

每种车子只造(工厂方法)一次(单例),后续使用同种车子都是同一辆车来运输!!!

import java.util.HashMap;

/**
 * 抽象享元角色:车
 */
interface Car {
    /**
     * 运输货物
     */
    void transport();
}

/**
 * 具体享元角色:拖拉机
 */
class Tractor implements Car {
    @Override
    public void transport() {
        System.out.println("拖拉机运输");
    }
}

/**
 * 具体享元角色:汽车
 */
class Automobile implements Car {
    @Override
    public void transport() {
        System.out.println("汽车运输");
    }
}

/**
 * 具体享元角色:火车
 */
class Train implements Car {
    @Override
    public void transport() {
        System.out.println("火车运输");
    }
}

/**
 * 享元工厂:汽车工厂
 */
class CarFactory {
    private HashMap<String, Car> cars = new HashMap<>();
    Car getCar(String carName) {
        Car car = cars.get(carName);
        if (car == null) {
            switch (carName) {
                case "火车":car = new Train();break;
                case "拖拉机":car = new Tractor();break;
                case "汽车":car = new Automobile();break;
                default: return null;
            }
            System.out.println("创建了:" + carName);
            cars.put(carName, car);
        }
        System.out.println("获取了:"+carName);
        return car;
    }
}

/**
 * 每种车子只造(工厂方法)一次(单例),后续使用同种车子都是同一个车子
 */
public class CarFlyWeight {
    public static void main(String[] args) {
        final CarFactory carFactory = new CarFactory();
        carFactory.getCar("汽车").transport();
        carFactory.getCar("汽车").transport();
        carFactory.getCar("拖拉机").transport();
        carFactory.getCar("拖拉机").transport();
        carFactory.getCar("火车").transport();
        carFactory.getCar("火车").transport();
    }
}
先展示下效果 https://pan.quark.cn/s/e81b877737c1 Node.js 是一种基于 Chrome V8 引擎的 JavaScript 执行环境,它使开发者能够在服务器端执行 JavaScript 编程,显著促进了全栈开发的应用普及。 在 Node.js 的开发流程中,`node_modules` 文件夹用于存储所有依赖的模块,随着项目的进展,该文件夹可能会变得异常庞大,其中包含了众多可能已不再需要的文件和文件夹,这不仅会消耗大量的硬盘空间,还可能减慢项目的加载时间。 `ModClean 2.0` 正是为了应对这一挑战而设计的工具。 `ModClean` 是一款用于清理 `node_modules` 的软件,其核心功能是移除那些不再被使用的文件和文件夹,从而确保项目的整洁性和运行效率。 `ModClean 2.0` 是此工具的改进版本,在原有功能上增加了更多特性,从而提高了清理工作的效率和精确度。 在 `ModClean 2.0` 中,用户可以设置清理规则,例如排除特定的模块或文件类型,以防止误删重要文件。 该工具通常会保留项目所依赖的核心模块,但会移除测试、文档、示例代码等非运行时必需的部分。 通过这种方式,`ModClean` 能够协助开发者优化项目结构,减少不必要的依赖,加快项目的构建速度。 使用 `ModClean` 的步骤大致如下:1. 需要先安装 `ModClean`,在项目的根目录中执行以下命令: ``` npm install modclean -g ```2. 创建配置文件 `.modcleanrc.json` 或 `.modcleanrc.js`,设定希望清理的规则。 比如,可能需要忽略 `LICENSE` 文件或整个 `docs`...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值