Java设计模式:四、行为型模式-06:观察者模式

文章目录

  • 一、定义:观察者模式
  • 二、模拟场景:观察者模式
    • 2.1 观察者模式
    • 2.2 引入依赖
    • 2.3 工程结构
    • 2.4 模拟摇号
      • 2.4.1 摇号服务接口
      • 2.4.2 摇号返回结果类
  • 三、违背方案:观察者模式
    • 3.0 引入依赖
    • 3.1 工程结构
    • 3.2 添加摇号接口和实现
      • 3.2.1 摇号服务接口
      • 3.2.2 摇号服务接口实现类
    • 3.3 单元测试
  • 四、改善代码:观察者模式
    • 4.0 引入依赖
    • 4.1 工程结构
    • 4.2 观察者模式结构图
    • 4.3 添加事件监听和管理器
      • 4.3.1 定义事件监听接口
      • 4.3.2 短信息事件监听接口实现
      • 4.3.3 MQ发送事件监听接口实现
      • 4.3.4 事件处理器
    • 4.4 摇号抽象类及其实现
      • 4.4.1 业务抽象类
      • 4.4.2 业务接口实现类
    • 4.5 单元测试
  • 五、总结:观察者模式

一、定义:观察者模式

在这里插入图片描述

  • **观察者模式:**当一个行为发生时传递信息给另外一个用户接收做出相应的处理,两者之间没有直接的耦合关联。
  • 除了生活中的场景外,在我们编程开发中也会常用到一些观察者的模式或者组件。例如:
    • 经常使用的 MQ 服务:虽然 MQ 服务是有一个通知中心并不是每一个类服务进行通知,但整体上也可以算作是观察者模式的思路设计。
    • 类似事件监听总线:让主线服务与其他辅线业务分离,为了使系统降低耦合和增强扩展性,也会使用观察者模式进行处理。

二、模拟场景:观察者模式

2.1 观察者模式

请添加图片描述

  • 模拟每次小客车指标摇号事件通知场景
  • 可能大部分人看到这个案例一定会想到自己每次摇号都不中的场景,收到一个遗憾的短信通知。当然目前的摇号系统不会给你发短信,而是由百度或者一些其他插件发的短信。
  • 那么假如这个类似的摇号功能由你来开发,并且需要对外部的用户做一些事件通知以及需要在主流外再添加一些额外的辅助流程时该如何处理呢?
    • 基本很多人对于这样的通知事件类的实现往往比较粗犷,直接在类里面添加就可以了。
      • ①考虑这可能不会怎么扩展,②是压根就没考虑过扩展。
    • 但如果你有仔细思考过你的核心类功能会发现,这里面有一些核心主链路,还有一部分是辅助功能。
      • 比如完成了某个行为后需要触发 MQ 给外部,以及做一些消息 PUSH 给用户等。
      • 这些都不算做是核心流程链路,是可以通过事件通知的方式进行处理。

2.2 引入依赖

pom.xml

<dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.62</version></dependency><!-- LOGGING begin --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.5</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>jcl-over-slf4j</artifactId><version>1.7.5</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.0.9</version><exclusions><exclusion><artifactId>slf4j-api</artifactId><groupId>org.slf4j</groupId></exclusion></exclusions></dependency>
</dependencies>

2.3 工程结构

design-19.0-0
|——src|——main|--java|--com.lino.design|-LotteryResult.java|-MinibusTargetService.java

2.4 模拟摇号

2.4.1 摇号服务接口

MinibusTargetService.java

package com.lino.design;/*** @description: 小客车指标调控服务*/
public class MinibusTargetService {/*** 模拟摇号** @param uId 用户编号* @return 结果*/public String lottery(String uId) {return Math.abs(uId.hashCode()) % 2 == 0 ?"恭喜你,编码".concat(uId).concat("在本次摇号中签"): "很遗憾,编码".concat(uId).concat("在本次摇号未中签或摇号资格已过期");}
}

2.4.2 摇号返回结果类

LotteryResult.java

package com.lino.design;import java.util.Date;/*** @description: 摇号结果类*/
public class LotteryResult {/*** 用户ID*/private String uId;/*** 摇号信息*/private String msg;/*** 业务时间*/private Date dateTime;public LotteryResult(String uId, String msg, Date dateTime) {this.uId = uId;this.msg = msg;this.dateTime = dateTime;}public String getuId() {return uId;}public void setuId(String uId) {this.uId = uId;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public Date getDateTime() {return dateTime;}public void setDateTime(Date dateTime) {this.dateTime = dateTime;}
}

三、违背方案:观察者模式

按照需求需要在原有的摇号接口中添加 MQ 消息发送以及短信息通知功能。
如果是最直接的方式那么可以直接在方法中补充功能即可。

3.0 引入依赖

<dependencies><dependency><groupId>com.lino</groupId><artifactId>design-19.0-0</artifactId><version>1.0-SNAPSHOT</version></dependency>
</dependencies>

3.1 工程结构

design-19.0-1
|——src|——main|--java|--com.lino.design|-LotteryService.java|-LotteryServiceImpl.java|--test|--com.lino.design.test|-ApiTest.java

3.2 添加摇号接口和实现

3.2.1 摇号服务接口

LotteryService.java

package com.lino.design;/*** @description: 摇号接口*/
public interface LotteryService {/*** 摇号** @param uId 用户编号* @return 摇号结果*/LotteryResult doDraw(String uId);
}

3.2.2 摇号服务接口实现类

LotteryServiceImpl.java

package com.lino.design;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;/*** @description: 摇号接口实现类*/
public class LotteryServiceImpl implements LotteryService {private Logger logger = LoggerFactory.getLogger(LotteryServiceImpl.class);private MinibusTargetService minibusTargetService = new MinibusTargetService();@Overridepublic LotteryResult doDraw(String uId) {// 摇号String lottery = minibusTargetService.lottery(uId);// 发短信logger.info("给用户 {} 发送短信通知(短信):{}", uId, lottery);// 发MQ信息logger.info("记录用户 {} 摇号结果(MQ):{}", uId, lottery);return new LotteryResult(uId, lottery, new Date());}
}
  • 从上面的方法实现中可以看到,整体过程包括三部分:摇号、发短信、发 MQ 消息,而这部分都是顺序调用的。
  • 除了 摇号 接口调用外,后面的两部分都是非核心主链路功能,而且会随着后续的业务需求发展而不断的调整和扩充,在这样的开发方式下就非常不利于维护。

3.3 单元测试

ApiTest.java

package com.lino.design.test;import com.alibaba.fastjson.JSON;
import com.lino.design.LotteryResult;
import com.lino.design.LotteryService;
import com.lino.design.LotteryServiceImpl;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** @description: 单元测试*/
public class ApiTest {private Logger logger = LoggerFactory.getLogger(ApiTest.class);@Testpublic void test() {LotteryService lotteryService = new LotteryServiceImpl();LotteryResult result = lotteryService.doDraw("2765789109876");logger.info("测试结果:{}", JSON.toJSONString(result));}
}
  • 测试过程中提供对摇号服务接口的调用

测试结果

17:06:14.931 [main] INFO  com.lino.design.LotteryServiceImpl - 给用户 2765789109876 发送短信通知(短信):很遗憾,编码2765789109876在本次摇号未中签或摇号资格已过期
17:06:14.931 [main] INFO  com.lino.design.LotteryServiceImpl - 记录用户 2765789109876 摇号结果(MQ):很遗憾,编码2765789109876在本次摇号未中签或摇号资格已过期
17:06:15.122 [main] INFO  com.lino.design.test.ApiTest - 测试结果:{"dateTime":1675760774946,"msg":"很遗憾,编码2765789109876在本次摇号未中签或摇号资格已过期","uId":"2765789109876"}

四、改善代码:观察者模式

4.0 引入依赖

<dependencies><dependency><groupId>com.lino</groupId><artifactId>design-19.0-0</artifactId><version>1.0-SNAPSHOT</version></dependency>
</dependencies>

4.1 工程结构

design-19.0-2
|——src|——main|--java|--com.lino.design|--event|		|--listener|		|		|--EventListener.java|		|		|--MessageEventListener.java|		|		|--MQEventListener.java|		|--EventManager.java|-LotteryService.java|-LotteryServiceImpl.java|--test|--com.lino.design.test|-ApiTest.java

4.2 观察者模式结构图

请添加图片描述

  • 从上图可以分为三大块:事件监听、事件处理、具体的业务流程。
    • 另外在业务流程中 LotteryService 定义的是抽象类,因为这样可以通过抽象类将事件功能屏蔽,外部业务流程开发者不需要知道具体的通知操作。
  • 右下角圆圈图表示的是核心流程与非核心流程的结构。
    • 一般在开发中会把主线流程开发完成后,再使用通知的方式处理辅助流程。他们可以是异步的,在 MQ 以及定时任务的处理下,保证最终一致性。

4.3 添加事件监听和管理器

4.3.1 定义事件监听接口

EventListener.java

package com.lino.design.event.listener;import com.lino.design.LotteryResult;/*** @description: 事件监听接口*/
public interface EventListener {/*** 监听事件** @param result 摇号结果*/void doEvent(LotteryResult result);
}
  • 接口定义了基本的事件类,这里如果方法的入参信息类型是变化的,可以使用泛型 T

4.3.2 短信息事件监听接口实现

MessageEventListener.java

package com.lino.design.event.listener;import com.lino.design.LotteryResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** @description: 短消息事件监听实现*/
public class MessageEventListener implements EventListener {private Logger logger = LoggerFactory.getLogger(MessageEventListener.class);@Overridepublic void doEvent(LotteryResult result) {logger.info("给用户 {} 发送短信通知(短信):{}", result.getuId(), result.getMsg());}
}

4.3.3 MQ发送事件监听接口实现

MQEventListener.java

package com.lino.design.event.listener;import com.lino.design.LotteryResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** @description: MQ事件监听实现*/
public class MQEventListener implements EventListener {private Logger logger = LoggerFactory.getLogger(MQEventListener.class);@Overridepublic void doEvent(LotteryResult result) {logger.info("记录用户 {} 摇号结果(MQ):{}", result.getuId(), result.getMsg());}
}

4.3.4 事件处理器

EventManager.java

package com.lino.design.event;import com.lino.design.LotteryResult;
import com.lino.design.event.listener.EventListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** @description: 事件处理器*/
public class EventManager {Map<Enum<EventType>, List<EventListener>> listeners = new HashMap<>();public EventManager(Enum<EventType>... operations) {for (Enum<EventType> operation : operations) {this.listeners.put(operation, new ArrayList<>());}}public enum EventType {/*** 事件类型*/MQ, Message}/*** 订阅** @param eventType 事件类型* @param listener  监听*/public void subscribe(Enum<EventType> eventType, EventListener listener) {List<EventListener> users = listeners.get(eventType);users.add(listener);}/*** 取消订阅** @param eventType 事件类型* @param listener  监听*/public void unsubscribe(Enum<EventType> eventType, EventListener listener) {List<EventListener> users = listeners.get(eventType);users.remove(listener);}/*** 通知** @param eventType 事件类型* @param result    结果*/public void notify(Enum<EventType> eventType, LotteryResult result) {List<EventListener> users = listeners.get(eventType);for (EventListener listener : users) {listener.doEvent(result);}}
}
  • 整个处理的实现上提供了三个主要方法:订阅 subscribe 、取消订阅 unsubscribe 、通知 notify 。这三个方法分别用于对监听事件的添加和使用。
  • 另外因为事件有不同的类型,这里使用率枚举的方式进行处理,也方便让外部在规定下使用事件,而不至于乱传信息。
    • 枚举:EventType.MQEventType.Message

4.4 摇号抽象类及其实现

4.4.1 业务抽象类

LotteryService.java

package com.lino.design;import com.lino.design.event.EventManager;
import com.lino.design.event.listener.MQEventListener;
import com.lino.design.event.listener.MessageEventListener;/*** @description: 摇号抽象类*/
public abstract class LotteryService {private EventManager eventManager;public LotteryService() {eventManager = new EventManager(EventManager.EventType.MQ, EventManager.EventType.Message);eventManager.subscribe(EventManager.EventType.MQ, new MQEventListener());eventManager.subscribe(EventManager.EventType.Message, new MessageEventListener());}public LotteryResult draw(String uId) {LotteryResult lotteryResult = doDraw(uId);eventManager.notify(EventManager.EventType.MQ, lotteryResult);eventManager.notify(EventManager.EventType.Message, lotteryResult);return lotteryResult;}/*** 执行摇号** @param uId 用户编号* @return 结果*/protected abstract LotteryResult doDraw(String uId);
}
  • 使用抽象类的方式定义实现方法,可以在方法中扩展需要的额外调用。
    • 并提供抽象类 abstract LotteryResult doDraw(String uId) ,让类的继承者实现。
    • 同时,方法的定义使用的是 protected ,也就是保证将来外部的调用方不会调用到此方法,只有调用到 draw(String uId) 才能完成事件通知。
  • 此种方式到实现是在抽象类中写好一个基本的方法,在方法中完成新增逻辑到同时,再增加抽象类的使用,而这个抽象的定义会由继承者实现。
  • 另外,在构造函数中提供了对事件的定义:
    • eventManager.subscribe(EventManager.EventType.MQ, new MQEventListener())
    • 在使用时也采用枚举的方式通知使用者,传了哪些类型 eventManager.EventType.Message,就执行哪些事件通知,按需添加。

4.4.2 业务接口实现类

LotteryServiceImpl.java

package com.lino.design;import java.util.Date;/*** @description: 摇号服务实现* @author: lingjian* @createDate: 2023/2/6 17:02*/
public class LotteryServiceImpl extends LotteryService {private MinibusTargetService minibusTargetService = new MinibusTargetService();@Overrideprotected LotteryResult doDraw(String uId) {// 摇号String lottery = minibusTargetService.lottery(uId);// 结果return new LotteryResult(uId, lottery, new Date());}
}
  • 业务流程的实现,没有额外的辅助流程,只有核心流程的处理。

4.5 单元测试

ApiTest.java

package com.lino.design.test;import com.alibaba.fastjson.JSON;
import com.lino.design.LotteryResult;
import com.lino.design.LotteryService;
import com.lino.design.LotteryServiceImpl;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** @description: 单元测试*/
public class ApiTest {private Logger logger = LoggerFactory.getLogger(ApiTest.class);@Testpublic void test_draw() {LotteryService lotteryService = new LotteryServiceImpl();LotteryResult result = lotteryService.draw("1000000101010019");logger.info("测试结果:{}", JSON.toJSONString(result));}
}

测试结果

19:45:45.314 [main] INFO  c.l.d.event.listener.MQEventListener - 记录用户 1000000101010019 摇号结果(MQ):恭喜你,编码1000000101010019在本次摇号中签
19:45:45.319 [main] INFO  c.l.d.e.l.MessageEventListener - 给用户 1000000101010019 发送短信通知(短信):恭喜你,编码1000000101010019在本次摇号中签
19:45:45.398 [main] INFO  com.lino.design.test.ApiTest - 测试结果:{"dateTime":1675770345311,"msg":"恭喜你,编码1000000101010019在本次摇号中签","uId":"1000000101010019"}

五、总结:观察者模式

  • 从基本的过程式开发,到使用观察者模式面向对象开发,可以看到使用设计模式改造后,拆分出来核心流程与辅助流程的代码。
    • 代码中的核心流程一般不会发生经常变化,辅助流程会随着业务的变化而变化,包括营销、裂变和促活等。
    • 因此使用设计模式编码就显得非常有必要。
  • 观察者模式从结构上满足开闭原则,当需要新增其他的监听事件或修改监听逻辑时,不需要改动事件处理类。
  • 观察者模式可能不能控制调用顺序以及需要做一些事件结果的返回操作,所以在使用的过程时需要考虑场景的适用性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/63012.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL 数据库常用命令大全(完整版)

文章目录 1. MySQL命令2. MySQL基础命令3. MySQL命令简介4. MySQL常用命令4.1 MySQL准备篇4.1.1 启动和停止MySQL服务4.1.2 修改MySQL账户密码4.1.3 MySQL的登陆和退出4.1.4 查看MySQL版本 4.2 DDL篇&#xff08;数据定义&#xff09;4.2.1 查询数据库4.2.2 创建数据库4.2.3 使…

JVM内存模型介绍

java内存中变量的存储位置 局部变量&#xff1a;方法中的局部变量存在于栈内存。每当程序调用一个方法时&#xff0c;系统都会为该方法建立一个方法栈&#xff0c;所在方法中声明的变量就放在方法栈中&#xff0c;方法结束系统会销毁该方法栈&#xff0c;在该方法中声明的变量随…

2023开学礼《乡村振兴战略下传统村落文化旅游设计》山东农大许少辉八一新书

2023开学礼《乡村振兴战略下传统村落文化旅游设计》山东农大许少辉八一新书

Java“魂牵”京东商品详情描述数据,京东商品详情API接口,京东API接口申请指南

要通过京东的API获取商品详情描述数据&#xff0c;您可以使用京东开放平台提供的接口来实现。以下是一种使用Java编程语言实现的示例&#xff0c;展示如何通过京东开放平台API获取商品详情&#xff1a; 首先&#xff0c;确保您已注册成为京东开放平台的开发者&#xff0c;并创…

时序预测 | MATLAB实现CNN-BiGRU卷积双向门控循环单元时间序列预测

时序预测 | MATLAB实现CNN-BiGRU卷积双向门控循环单元时间序列预测 目录 时序预测 | MATLAB实现CNN-BiGRU卷积双向门控循环单元时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.MATLAB实现CNN-BiGRU卷积双向门控循环单元时间序列预测&#xff1b; 2.运行环境…

cmd: Union[List[str], str], ^ SyntaxError: invalid syntax

跑项目在调用from easyprocess import EasyProcess 遇到报错&#xff1a; cmd: Union[List[str], str], ^ SyntaxError: invalid syntax猜测是EasyProcess版本与python版本不对应 pip show EasyProcess查证一下&#xff1a; WARNING: pip is being invoked by an old…

OPENCV实现暴力特征匹配

# -*- coding:utf-8 -*- """ 作者:794919561 日期:2023/9/1 """ import cv2 import numpy as np# 读

TensorFlow 的基本概念和使用场景介绍

文章目录 一、TensorFlow基本概念1. 张量&#xff08;Tensor&#xff09;2. 计算图&#xff08;Computation Graph&#xff09;3. 会话&#xff08;Session&#xff09; 二、TensorFlow使用场景1. 机器学习&#xff08;Machine Learning&#xff09;2. 计算机视觉&#xff08;C…

D358周赛复盘:哈希表模拟⭐⭐+链表乘法翻倍运算(先反转)⭐⭐⭐

文章目录 2815.数组中的最大数对和思路完整版 2816.翻倍以链表形式表示的数字&#xff08;先反转&#xff0c;再处理进位&#xff09;思路完整版 补充&#xff1a;206.反转链表&#xff08;双指针法&#xff09;完整版 2817.限制条件下元素之间的最小绝对差&#xff08;cpp不知…

20230901工作心得:IDEA列操作lambda表达式加强版用法

今天是中小学开学时间&#xff0c;亦是9月的开始&#xff0c;继续努力。 今日收获较大的有四个地方&#xff0c;先说这四点。 1、IDEA列操作 使用场景&#xff1a;需要批量将Excel表格里的数据插入到数据库中&#xff0c;此时需要写大量的insert SQL语句。 比如像这样的&am…

RunnerGo:轻量级、全栈式、易用性和高效性的测试工具

随着软件测试的重要性日益凸显&#xff0c;市场上的测试工具也日益丰富。RunnerGo作为一款基于Go语言研发的开源测试平台&#xff0c;以其轻量级、全栈式、易用性和高效性的特点&#xff0c;在测试工具市场中逐渐脱颖而出。 RunnerGo是一款轻量级的测试工具&#xff0c;使用Go…

python爬虫数据解析xpath

一、环境配置 1、安装xpath 下载地址&#xff1a;百度网盘 请输入提取码 第一步&#xff1a; 下载好文件后会得到一个没有扩展名的文件&#xff0c;重命名该文件将其改为.rar或者.zip等压缩文件&#xff0c;解压之后会得到一个.crx文件和一个.pem文件。新建一个文件夹&…

《论文阅读21》Equivariant Multi-View Networks

一、论文 研究领域&#xff1a;计算机视觉 | 多视角数据处理中实现等变性论文&#xff1a;Equivariant Multi-View Networks ICCV 2019 论文链接视频链接 二、论文简述 在计算机视觉中&#xff0c;模型在不同视角下对数据&#xff08;例如&#xff0c;点云、图像等&#xff0…

【python爬虫】—豆瓣电影Top250

豆瓣电影Top250 豆瓣榜单简介需求描述Python实现 豆瓣榜单简介 豆瓣电影 Top 250 榜单是豆瓣网站上列出的评分最高、受观众喜爱的电影作品。这个榜单包含了一系列优秀的影片&#xff0c;涵盖了各种类型、不同国家和时期的电影。 需求描述 使用python爬取top250电影&#xff…

AMEYA360代理 | 佰维eMMC、LPDDR存储芯片赋能电视终端流畅体验

5G、AI、VR、AR等技术的发展&#xff0c;助推智能电视、机顶盒等电视终端成为智能家居领域不可忽视的重要设备。随着4K超高清(UHD)技术、虚拟现实技术(VR)和增强现实技术(AR)的普及&#xff0c;并向8K超高清技术不断渗透&#xff0c;电视终端将可以为消费者提供更清晰的视觉体验…

vue通过draggable实现拖拽功能

1. 官方文档 2. 安装 yarn add vuedraggable npm i -S vuedraggable <script src"//cdnjs.cloudflare.com/ajax/libs/Vue.Draggable/2.20.0/vuedraggable.umd.min.js"></script> 3. 其他组件&#xff1a; sortablejs.js拖拽 非官网文档 npm install …

16 Linux之JavaEE定制篇-搭建JavaEE环境

16 Linux之JavaEE定制篇-搭建JavaEE环境 文章目录 16 Linux之JavaEE定制篇-搭建JavaEE环境16.1 概述16.2 安装JDK16.3 安装tomcat16.4 安装idea2020*16.5 安装mysql5.7 学习视频来自于B站【小白入门 通俗易懂】2021韩顺平 一周学会Linux。可能会用到的资料有如下所示&#xff0…

Windows右键添加用 VSCODE 打开

1.安装VSCODE时 安装时会有个选项来添加&#xff0c;如下&#xff1a; ①将“通过code 打开“操作添加到windows资源管理器文件上下文菜单 ②将“通过code 打开”操作添加到windows资源管理器目录上下文菜单 说明&#xff1a;①②勾选上&#xff0c;可以对文件&#xff0c;目…

C#,《小白学程序》第八课:列表(List)应用之二“编制高铁列车时刻表”

1 文本格式 /// <summary> /// 车站信息类 class /// </summary> public class Station { /// <summary> /// 编号 /// </summary> public int Id { get; set; } 0; /// <summary> /// 车站名 /// </summary&g…

Windows docker desktop 基于HyperV的镜像文件迁移到D盘

Docker desktop的HyperV镜像文件&#xff0c;默认是在C盘下 C:\ProgramData\DockerDesktop\vm-data\DockerDesktop.vhdx如果部署的软件较多&#xff0c;文件较大&#xff0c;或者产生日志&#xff0c;甚至数据等&#xff0c;这将会使此文件越来越大&#xff0c;容易导致C盘空间…