我说EasyExcel源码里用了十种设计模式,还不进来看看

文章介绍了EasyExcel如何通过基于流的SAX解析、内存管理优化以及运用各种设计模式(如工厂、建造者、策略等)来减少内存消耗。此外,文章还提到EasyExcel不支持图片的原因,并提及其他可能的扩展方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

你用过EasyExcel吗

为什么用呢

EasyExcel 能够减少内存消耗的关键在于它使用了基于流的读写方式,特别是在读取大型Excel文件时,它采用了事件驱动的SAX(Simple API for XML)解析模式。下面是EasyExcel减少内存消耗的几个主要原因:

  1. 基于SAX的读取

    • 在读取Excel文件时,EasyExcel不会一次性将整个文件加载到内存中,而是采用了SAX模型,这意味着它会顺序读取文件的每一行数据,逐行进行处理,不需要将整个Excel文档放入内存。
    • 它会触发事件(如开始读取行、单元格等),开发者可以通过实现事件处理器(Listener)来处理这些事件,这样就可以在读取每一行时进行数据处理,而不必等待整个文档加载完毕。
  2. 基于流的写入

    • 在写入Excel文件时,EasyExcel同样采用了基于流的方式,它会创建一个XML流,并逐行写入数据到这个流中,然后将流写入到磁盘上的文件中。
    • 这种方式意味着在写Excel文件的过程中,不需要在内存中维护整个Excel对象模型,只需维护当前正在写入的少量数据。
  3. 内存管理

    • EasyExcel在内部做了一些优化,比如重用对象、减少临时对象的创建等,这些都有助于减少内存的使用。
  4. 限制缓存大小

    • EasyExcel允许开发者设置缓存的大小,例如,在写入操作中,可以设置一个较小的缓存来存储即将写入磁盘的数据,这样可以进一步减少内存的使用。

通过上述方式,EasyExcel能够在处理大型Excel文件时显著减少内存的消耗,使得即使在内存受限的环境下也能高效地处理Excel文件。这使得EasyExcel非常适合在大数据导入导出的场景中使用,尤其是当涉及到成千上万甚至百万行数据的时候。

那它支持读取图片吗

关于EasyExcel不支持图片的问题,这主要是因为EasyExcel主要关注于数据的读写,而Excel中的图片和图表等元素处理相对复杂,它们不仅需要处理数据,还涉及到位置、大小、格式等多方面的属性。此外,图片的处理需要更多的内存和处理时间,这可能会影响到EasyExcel处理大量数据时的性能和效率。

EasyExcel 的设计哲学是“极简”,所以它可能没有包括对图片等复杂元素的支持,以保持库的轻量级和高性能。如果你需要在Excel中处理图片,你可能需要考虑使用 Apache POI 库,这是一个功能更为全面的Excel处理库,它支持包括图片在内的各种复杂元素的操作,但相应的,它的性能和内存消耗也会比 EasyExcel 高。

如果你需要在使用 EasyExcel 的同时处理图片,你可能需要结合使用 Apache POI 来实现这一功能。例如,你可以使用 EasyExcel 来处理数据部分,然后使用 Apache POI 来添加图片等元素。这样做虽然会增加一些复杂性,但可以让你同时利用两者的优点。

 

好了,下面说说他的源码实现的奥妙

EasyExcel 在其源码中运用了多种设计模式和巧妙的设计来保证代码的可维护性、扩展性和灵活性。以下是一些在 EasyExcel 源码中常见的设计模式和设计思想:

  1. 工厂模式(Factory Pattern)
    EasyExcel 在创建对象时,如读写器(Reader、Writer)的创建,经常使用工厂模式。这样做可以隐藏创建逻辑的复杂性,并提供一个统一的接口来创建对象。

具体实现:

public class ReaderFactory {
    public static ExcelReader createReader(ExcelFileType fileType) {
        if (fileType == ExcelFileType.XLS) {
            return new ExcelXlsReader();
        } else if (fileType == ExcelFileType.XLSX) {
            return new ExcelXlsxReader();
        }
        throw new IllegalArgumentException("Unsupported file type");
    }
}

public interface ExcelReader {
    void read();
}

public class ExcelXlsReader implements ExcelReader {
    @Override
    public void read() {
        // 读取XLS文件的逻辑
    }
}

public class ExcelXlsxReader implements ExcelReader {
    @Override
    public void read() {
        // 读取XLSX文件的逻辑
    }
}

// 使用工厂创建读取器
ExcelReader reader = ReaderFactory.createReader(ExcelFileType.XLSX);
reader.read();

2.建造者模式(Builder Pattern)
EasyExcel 使用建造者模式来简化复杂对象的构建过程。例如,在配置一个Excel读取或写入操作时,可以链式调用多个配置方法来设置不同的选项,这样的设计提高了代码的可读性和易用性。

具体实现:

public class ExcelWriterBuilder {
    private String path;
    private ExcelFileType fileType;

    public ExcelWriterBuilder path(String path) {
        this.path = path;
        return this;
    }

    public ExcelWriterBuilder fileType(ExcelFileType fileType) {
        this.fileType = fileType;
        return this;
    }

    public ExcelWriter build() {
        // 根据设置的参数创建ExcelWriter
        return new ExcelWriter(this.path, this.fileType);
    }
}

public class ExcelWriter {
    private String path;
    private ExcelFileType fileType;

    public ExcelWriter(String path, ExcelFileType fileType) {
        this.path = path;
        this.fileType = fileType;
        // 更多初始化代码
    }

    public void write() {
        // 写Excel的逻辑
    }
}

// 使用建造者模式构建写入器
ExcelWriter writer = new ExcelWriterBuilder()
                        .path("/path/to/excel")
                        .fileType(ExcelFileType.XLSX)
                        .build();
writer.write();
  1. 策略模式(Strategy Pattern)
    对于不同的操作,EasyExcel 允许用户定义自己的处理策略。例如,在解析单元格数据时,可以通过实现自定义的转换器(Converter)来处理不同类型的数据。

public interface CellDataHandler {
    void handle(CellData cellData);
}

public class NumberDataHandler implements CellDataHandler {
    @Override
    public void handle(CellData cellData) {
        // 处理数字类型的数据
    }
}

public class StringDataHandler implements CellDataHandler {
    @Override
    public void handle(CellData cellData) {
        // 处理字符串类型的数据
    }
}

public class CellDataReader {
    private CellDataHandler handler;

    public CellDataReader(CellDataHandler handler) {
        this.handler = handler;
    }

    public void read(CellData cellData) {
        handler.handle(cellData);
    }
}

// 使用策略模式处理单元格数据
CellDataReader reader = new CellDataReader(new NumberDataHandler());
reader.read(cellData);


 

  1. 模板方法模式(Template Method Pattern)
    EasyExcel 在处理读取和写入操作时,会定义一个算法的骨架,将算法的步骤固定在高层代码中,而将一些步骤的实现延迟到子类中。这样,算法的结构被保持不变,同时可以让子类在不改变算法结构的情况下重定义算法的某些特定步骤。

public abstract class ExcelFileProcessor {
    public final void processFile() {
        openFile();
        readData();
        processData();
        closeFile();
    }

    protected abstract void openFile();
    protected abstract void readData();
    protected abstract void processData();
    protected abstract void closeFile();
}

public class XlsxFileProcessor extends ExcelFileProcessor {
    @Override
    protected void openFile() {
        // 打开XLSX文件
    }

    @Override
    protected void readData() {
        // 读取数据
    }

    @Override
    protected void processData() {
        // 处理数据
    }

    @Override
    protected void closeFile() {
        // 关闭文件
    }
}

// 使用模板方法
ExcelFileProcessor processor = new XlsxFileProcessor();
processor.processFile();


 

  1. 单例模式(Singleton Pattern)
    对于一些全局使用的配置和管理类,EasyExcel 采用单例模式来确保全局只有一个实例,这有助于减少内存的使用并避免重复的初始化操作。

public class Configuration {
    private static Configuration instance;

    private Configuration() {
        // 私有构造函数,防止外部直接创建实例
    }

    public static synchronized Configuration getInstance() {
        if (instance == null) {
            instance = new Configuration();
        }
        return instance;
    }

    // 配置相关的方法
}

// 使用单例获取配置实例
Configuration config = Configuration.getInstance();
  1. 观察者模式(Observer Pattern)
    在读取Excel时,EasyExcel 允许用户定义监听器(Listener),这些监听器可以看作是观察者,它们会在读取过程中的特定时刻被触发,用户可以在这些监听器中定义自己的处理逻辑。

public interface ReadListener {
    void onReadRow(RowData rowData);
}

public class ExcelReader {
    private List<ReadListener> listeners = new ArrayList<>();

    public void addReadListener(ReadListener listener) {
        listeners.add(listener);
    }

    public void read() {
        // 读取Excel的逻辑
        // ...
        // 当读取一行时通知监听器
        for (ReadListener listener : listeners) {
            listener.onReadRow(rowData);
        }
    }
}

public class CustomReadListener implements ReadListener {
    @Override
    public void onReadRow(RowData rowData) {
        // 处理读取到的行
    }
}

// 使用观察者模式添加监听器
ExcelReader reader = new ExcelReader();
reader.addReadListener(new CustomReadListener());
reader.read();
  1. 装饰器模式(Decorator Pattern)
    EasyExcel 允许用户对输出的Excel进行格式化,这通过一系列的装饰器完成,每个装饰器添加一层特定的格式化功能。

public interface ExcelExport {
    void exportData();
}

public class SimpleExcelExport implements ExcelExport {
    @Override
    public void exportData() {
        // 导出数据的基本实现
    }
}

public abstract class ExcelExportDecorator implements ExcelExport {
    protected ExcelExport wrappedExport;

    public ExcelExportDecorator(ExcelExport wrappedExport) {
        this.wrappedExport = wrappedExport;
    }

    @Override
    public void exportData() {
        wrappedExport.exportData();
    }
}

public class StyledExcelExportDecorator extends ExcelExportDecorator {
    public StyledExcelExportDecorator(ExcelExport wrappedExport) {
        super(wrappedExport);
    }

    @Override
    public void exportData() {
        super.exportData();
        // 添加样式的额外逻辑
    }
}

// 使用装饰器模式增加额外功能
ExcelExport export = new SimpleExcelExport();
export = new StyledExcelExportDecorator(export);
export.exportData();
  1. 责任链模式(Chain of Responsibility Pattern)
    在处理Excel读写的过程中,可能需要通过多个处理器对数据进行处理。责任链模式允许将这些处理器串联起来,形成一个链条,一个处理器处理完数据后将其传递给下一个处理器,直到所有处理器都对数据执行了操作。

public abstract class DataProcessor {
    protected DataProcessor nextProcessor;

    public DataProcessor setNext(DataProcessor nextProcessor) {
        this.nextProcessor = nextProcessor;
        return nextProcessor;
    }

    public abstract void process(Data data);
}

public class ValidationProcessor extends DataProcessor {
    @Override
    public void process(Data data) {
        // 验证数据
        if (nextProcessor != null) {
            nextProcessor.process(data);
        }
    }
}

public class TransformationProcessor extends DataProcessor {
    @Override
    public void process(Data data) {
        // 转换数据
        if (nextProcessor != null) {
            nextProcessor.process(data);
        }
    }
}

// 构建责任链
DataProcessor validator = new ValidationProcessor();
DataProcessor transformer = validator.setNext(new TransformationProcessor());

// 启动链条
validator.process(data);

这些设计模式在我们日常开发中都可以进行借鉴使用,使代码代码结构清晰,功能分离,便于理解和维护 

有用就赶紧收藏起来吧,骚年们

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码上代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值