Spring 设计模式之工厂模式

Spring 设计模式之工厂模式

  • 一、简单工厂模式(静态工厂模式)
    • Spring框架中的体现
    • 举例说明
    • Java代码实现
  • 二、工厂方法模式
    • 举例说明
    • Java代码示例
  • 三、抽象工厂模式
    • 举例说明
    • Java代码示例

在软件开发领域,设计模式 是解决常见问题的最佳实践。
Spring 框架作为 Java 生态中的佼佼者,其成功在很大程度上 归功于对设计模式的巧妙运用。
“Spring 中用到了哪些设计模式?”,这个问题,在 面试 中也比较常见,在此进行整理。

一、简单工厂模式(静态工厂模式)

简单工厂模式又叫静态工厂方法模式,就是建立一个工厂类(是类的形式,而不是接口),对实现了同一接口的一些类进行实例的创建。
其核心是 由一个工厂类根据传入的参数,动态决定创建哪一个产品类的实例。

优点

  1. 责任分割:工厂类包含判断逻辑,决定何时创建哪个产品实例,客户端仅负责“消费”产品。
  2. 灵活性:根据外界信息决定创建哪个具体对象,客户端无需直接创建对象。
  3. 低耦合:外界与具体产品类隔离,降低耦合性。
  4. 结构优化:明确区分职责和权力,利于软件体系结构优化。

缺点

  1. 扩展困难:增加或删除产品需修改工厂逻辑,系统扩展性受限。
  2. 违背OCP:修改工厂逻辑可能导致过于复杂,违背开放-封闭原则(对新增开放,对修改关闭)。
  3. 无法继承:静态工厂方法使得工厂角色无法形成基于继承的等级结构。

Spring框架中的体现

举例说明

您走进了一家名为“万能奶茶店”的饮品店。这家店里只有一位店员(相当于工厂类),他负责制作店里所有种类的奶茶。当您告诉店员您想喝的奶茶类型(比如珍珠奶茶、抹茶拿铁或草莓奶茶)时,店员会根据您的要求为您精心制作一杯(即创建奶茶对象)。

然而,如果这家奶茶店想要推出新口味的奶茶(比如芒果奶茶),店员就需要学习新口味的制作方法,并且还要在菜单上添加这个新选项。这就意味着店员(即工厂类)的职责范围需要扩大,因此其代码也需要相应地进行修改,以支持这种新口味的奶茶。

这种模式下,每当有新产品加入时,都需要对工厂类进行修改,这可能会影响到系统的稳定性和可维护性。

Java代码实现

下面是一个使用简单工厂模式来实现上述场景的Java示例。

知识小贴士:
咖啡对象也可以用类来创建,但是如果是类的话,就必须把咖啡类定义为抽象类(public abstract class MilkTea )是为了强制子类实现必要的方法,防止直接实例化,以及(可选地)提供共享代码。

// 奶茶类,作为所有奶茶的基类  
interface MilkTea {  // 制作奶茶的方法  public abstract void make();  
}  // 珍珠奶茶类  
class PearlMilkTea implements MilkTea {  @Override  public void make() {  System.out.println("制作珍珠奶茶");  }  
}  // 抹茶拿铁类  
class MatchaLatte implements MilkTea {  @Override  public void make() {  System.out.println("制作抹茶拿铁");  }  
}  // 草莓奶茶类  
class StrawberryMilkTea implements MilkTea {  @Override  public void make() {  System.out.println("制作草莓奶茶");  }  
}  // 简单工厂类,负责创建所有种类的奶茶  
class SimpleFactory {  // 根据奶茶类型创建对应的奶茶对象  public static MilkTea createMilkTea(String type) {  switch (type) {  case "pearl":  return new PearlMilkTea();  case "matcha":  return new MatchaLatte();  case "strawberry":  return new StrawberryMilkTea();  default:  throw new IllegalArgumentException("未知的奶茶类型");  }  }  
}  // 客户端测试类  
public class SimpleFactoryClient {  public static void main(String[] args) {  MilkTea tea1 = SimpleFactory.createMilkTea("pearl");  tea1.make(); // 输出:制作珍珠奶茶  MilkTea tea2 = SimpleFactory.createMilkTea("matcha");  tea2.make(); // 输出:制作抹茶拿铁  // 如果添加新口味的奶茶,比如芒果奶茶,需要修改SimpleFactory类  }  
}

如果这家奶茶店想要推出新口味的奶茶(比如芒果奶茶),店员就需要学习新口味的制作方法,并且还要在菜单上添加这个新选项。这就意味着店员(即工厂类)的职责范围需要扩大,因此其代码也需要相应地进行修改,以支持这种新口味的奶茶。

// 新增芒果奶茶类  
class MangoMilkTea implements MilkTea {  @Override  public void make() {  System.out.println("制作芒果奶茶");  }  
}  // 简单工厂类,负责创建所有种类的奶茶(已修改以支持芒果奶茶)  
class SimpleFactory {  // 根据奶茶类型创建对应的奶茶对象(已修改以支持芒果奶茶)  public static MilkTea createMilkTea(String type) {  switch (type) {  case "pearl":  return new PearlMilkTea();  case "matcha":  return new MatchaLatte();  case "strawberry":  return new StrawberryMilkTea();  case "mango": // 新增的芒果奶茶选项  return new MangoMilkTea();  default:  throw new IllegalArgumentException("未知的奶茶类型");  }  }  
}  // 客户端测试类(可以添加测试芒果奶茶的代码)  
public class SimpleFactoryClient {  public static void main(String[] args) {  MilkTea tea1 = SimpleFactory.createMilkTea("pearl");  tea1.make(); // 输出:制作珍珠奶茶  MilkTea tea2 = SimpleFactory.createMilkTea("matcha");  tea2.make(); // 输出:制作抹茶拿铁  MilkTea tea3 = SimpleFactory.createMilkTea("strawberry");  tea3.make(); // 输出:制作草莓奶茶  // 测试新口味的芒果奶茶  MilkTea tea4 = SimpleFactory.createMilkTea("mango");  tea4.make(); // 输出:制作芒果奶茶  }  
}

如果 类存在@Autowired 的使用时,new 对象的操作就需要换成 ApplicationContext 去获取

// 珍珠奶茶类,现在是一个 Spring 组件  
@Component  
class PearlMilkTea implements MilkTea {  @Autowired private PearMapper pearMapper;  @Override  public void make() {  // 使用 pearMapper 做一些事情(例如查询数据库)  pearMapper.select()// ...  System.out.println("制作珍珠奶茶");  }  
}  class SimpleFactory implements ApplicationContextAware {ApplicationContext applicationContext;// 根据奶茶类型创建对应的奶茶对象  public static MilkTea createMilkTea(String type) {switch (type) {case "pearl":return applicationContext.getBean(PearlMilkTea.Class);case "matcha":return new MatchaLatte();case "strawberry":return new StrawberryMilkTea();default:throw new IllegalArgumentException("未知的奶茶类型");}}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext=applicationContext;}
}

二、工厂方法模式

工厂方法模式:定义了一个用于创建对象的接口,让子类决定实例化哪一个类。
工厂方法使一个类的实例化延迟到子类。

优点

  1. 单一职责:每个具体工厂类只负责创建一种产品,代码更加简洁。
  2. 扩展性强:完全满足开闭原则(OCP:对新增开放,对修改关闭),新增产品类时无需修改已有代码,只需新增具体产品类和对应工厂类。

缺点

  1. 增加开发量:每增加一个新产品,都需要新增一个具体产品类和一个对应的具体工厂类,增加了额外的开发工作量。
  2. 维护复杂:当需要修改多个产品类时,可能需要同时修改多个对应的工厂类,维护成本增加。

举例说明

您来到了一个奶茶一条街,这里有多家不同品牌的奶茶店,比如“A品牌奶茶店”和“B品牌奶茶店”, 奶茶店(品牌) 本身就相当于工厂。每家店都有自己的特色奶茶(比如珍珠奶茶、抹茶拿铁和草莓奶茶),并且每家店都有自己的店员(相当于具体工厂类)来负责制作这些奶茶。

您可以根据自己的喜好选择一家奶茶店,然后走进店里告诉店员您想喝的奶茶类型。
店员会根据自己店铺的特色为您制作一杯奶茶。
如果某家店想要推出新口味的奶茶(比如芒果奶茶),他们只需要在自己的店铺里添加这种新口味的奶茶,并培训店员掌握新的制作方法。
这样,其他店铺就不会受到影响,因为每家店都有自己的店员和独特的制作流程。

这种模式下,新增产品时只需要修改对应的具体工厂类,而无需修改工厂接口或现有的其他具体工厂类,从而提高了系统的扩展性和灵活性。

Java代码示例

// 奶茶接口  
interface MilkTea {  void make();  
}  // 珍珠奶茶类  
class PearlMilkTeaImpl implements MilkTea {  @Override  public void make() {  System.out.println("制作珍珠奶茶");  }  
}  // 抹茶拿铁类  
class MatchaLatteImpl implements MilkTea {  @Override  public void make() {  System.out.println("制作抹茶拿铁");  }  
}  // 草莓奶茶类  
class StrawberryMilkTeaImpl implements MilkTea {  @Override  public void make() {  System.out.println("制作草莓奶茶");  }  
}  // 工厂接口  
interface MilkTeaFactory {  MilkTea createMilkTea();  
}  // A品牌奶茶店工厂类  
class BrandAMilkTeaFactory implements MilkTeaFactory {  @Override  public MilkTea createMilkTea() {  return new PearlMilkTeaImpl(); // 假设A品牌只卖珍珠奶茶  }  
}  // B品牌奶茶店工厂类  
class BrandBMilkTeaFactory implements MilkTeaFactory {  @Override  public MilkTea createMilkTea() {  return new MatchaLatteImpl(); // 假设B品牌只卖抹茶拿铁  }  
}  // 客户端测试类  
public class FactoryMethodClient {  public static void main(String[] args) {  MilkTeaFactory factoryA = new BrandAMilkTeaFactory();  MilkTea teaA = factoryA.createMilkTea();  teaA.make(); // 输出:制作珍珠奶茶  MilkTeaFactory factoryB = new BrandBMilkTeaFactory();  MilkTea teaB = factoryB.createMilkTea();  teaB.make(); // 输出:制作抹茶拿铁  // 如果A品牌想要推出新口味的奶茶,// 比如芒果奶茶,只需要在BrandAMilkTeaFactory中添加新的实现  }  
}

如果A品牌奶茶店想要推出新口味的奶茶,比如芒果奶茶

// 奶茶接口  
interface MilkTea {  void make();  
}  // 珍珠奶茶类  
class PearlMilkTeaImpl implements MilkTea {  @Override  public void make() {  System.out.println("制作珍珠奶茶");  }  
}  // 抹茶拿铁类  
class MatchaLatteImpl implements MilkTea {  @Override  public void make() {  System.out.println("制作抹茶拿铁");  }  
}  // 草莓奶茶类  
class StrawberryMilkTeaImpl implements MilkTea {  @Override  public void make() {  System.out.println("制作草莓奶茶");  }  
}  // 新增芒果奶茶类  
class MangoMilkTeaImpl implements MilkTea {  @Override  public void make() {  System.out.println("制作芒果奶茶");  }  
}  // 奶茶类型枚举  
enum MilkTeaType {  PEARL,  MATCHA_LATTE,  STRAWBERRY,  MANGO // 新增芒果奶茶类型  
}  // 工厂接口(稍作修改以支持类型参数)  
interface MilkTeaFactory {  MilkTea createMilkTea(MilkTeaType type); // 引入类型参数  
}  // A品牌奶茶店工厂类(修改以支持多种奶茶)  
class BrandAMilkTeaFactory implements MilkTeaFactory {  @Override  public MilkTea createMilkTea(MilkTeaType type) {  switch (type) {  case PEARL:  return new PearlMilkTeaImpl();  case MANGO: // 新增对芒果奶茶的支持  return new MangoMilkTeaImpl();  default:  throw new IllegalArgumentException("Unsupported MilkTeaType: " + type);  }  }  
}  // B品牌奶茶店工厂类(保持不变,但也可以按类似方式扩展)  
class BrandBMilkTeaFactory implements MilkTeaFactory {  @Override  public MilkTea createMilkTea(MilkTeaType type) {  // 这里为了简单起见,我们只提供一种奶茶,但可以根据需要扩展  if (type == MilkTeaType.MATCHA_LATTE) {  return new MatchaLatteImpl();  } else {  throw new IllegalArgumentException("Unsupported MilkTeaType: " + type);  }  }  
}  // 客户端测试类  
public class FactoryMethodClient {  public static void main(String[] args) {  MilkTeaFactory factoryA = new BrandAMilkTeaFactory();  MilkTea teaA1 = factoryA.createMilkTea(MilkTeaType.PEARL);  teaA1.make(); // 输出:制作珍珠奶茶  MilkTea teaA2 = factoryA.createMilkTea(MilkTeaType.MANGO); // 新增对芒果奶茶的创建  teaA2.make(); // 输出:制作芒果奶茶  MilkTeaFactory factoryB = new BrandBMilkTeaFactory();  MilkTea teaB = factoryB.createMilkTea(MilkTeaType.MATCHA_LATTE);  teaB.make(); // 输出:制作抹茶拿铁  }  
}

三、抽象工厂模式

定义了一个接口用于创建相关或依赖对象的家族,而无需明确指定具体类。
该模式是对工厂方法模式的进一步升级,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。

优点:

  1. 高内聚低耦合:抽象工厂模式将产品的创建与使用分离,降低了客户端代码与产品类之间的耦合度,同时产品族内的产品以高内聚的形式存在,有助于代码的维护和管理。
  2. 扩展性好:完全满足开闭原则(OCP:对新增开放,对修改关闭),当需要添加新的产品族时,只需要添加一个新的具体工厂类和相应的产品类,而不需要修改原有的客户端代码。
  3. 灵活性高:通过抽象工厂模式设计,系统可以更加灵活地应对需求的变化,新增组件或平台时,只需新增新的抽象组件和具体平台工厂,无需修改已有代码。

缺点:

  1. 增加复杂性:抽象工厂模式增加了系统的抽象性和复杂性,可能导致系统难以理解和维护。
  2. 扩展新产品困难:如果只需要添加新的产品而不是新的产品族,那么抽象工厂模式可能会变得笨拙,因为需要修改所有的工厂接口和工厂实现类。

举例说明

您来到了一个更加高级的奶茶广场,这里不仅有奶茶店,还有卖杯子、吸管等配件的店铺。而且,这些店铺都是连锁经营的,比如“热带风味奶茶店”和“经典风味奶茶店”,它们不仅提供奶茶,还提供与奶茶风格相匹配的杯子和吸管等配件。

您可以选择自己喜欢的奶茶店品牌,然后走进这家店。在这里,您不仅可以喝到他们特色的奶茶,还可以买到与奶茶风格相匹配的杯子和吸管等配件。这些产品都是一系列相互关联的,共同构成了一个产品族。

如果某家店想要推出新口味的奶茶或者新风格的杯子和吸管(比如蓝莓奶茶或陶瓷杯子),他们只需要在自己的品牌内部进行更新和调整。这样,您就可以在不同的品牌之间自由选择,并且每次都能得到一整套风格一致的奶茶及其配件。

这种模式下,新增产品族时只需要在对应的具体工厂类中添加新的产品创建方法,而无需修改抽象工厂接口或现有的其他具体工厂类(除非新增的产品引入了新的产品等级)。这进一步提高了系统的扩展性和灵活性。

Java代码示例

// 奶茶接口  
interface MilkTea {  void make();  
}  // 杯子接口  
interface Cup {  void show();  
}  // 珍珠奶茶类  
class PearlMilkTeaImpl implements MilkTea {  @Override  public void make() {  System.out.println("制作珍珠奶茶");  }  
}  // 抹茶拿铁类  
class MatchaLatteImpl implements MilkTea {  @Override  public void make() {  System.out.println("制作抹茶拿铁");  }  
}  // 塑料杯类  
class PlasticCupImpl implements Cup {  @Override  public void show() {  System.out.println("这是塑料杯");  }  
}  // 陶瓷杯类  
class CeramicCupImpl implements Cup {  @Override  public void show() {  System.out.println("这是陶瓷杯");  }  
}  // 抽象工厂接口  
interface AbstractFactory {  MilkTea createMilkTea();  Cup createCup();  
}  // 热带风味奶茶店工厂类  
class TropicalFlavorFactory implements AbstractFactory {  @Override  public MilkTea createMilkTea() {  //制作珍珠奶茶return new PearlMilkTeaImpl();  }  @Override  public Cup createCup() { //塑料杯return new PlasticCupImpl();  }  
}  // 经典风味奶茶店工厂类  
class ClassicFlavorFactory implements AbstractFactory {  @Override  public MilkTea createMilkTea() {  //制作抹茶拿铁return new MatchaLatteImpl();  }  @Override  public Cup createCup() { //陶瓷杯return new CeramicCupImpl();  }  
}  // 客户端测试类  
public class AbstractFactoryClient {  public static void main(String[] args) {  AbstractFactory factory1 = new TropicalFlavorFactory();  MilkTea tea1 = factory1.createMilkTea();  Cup cup1 = factory1.createCup();  tea1.make(); // 输出:制作珍珠奶茶  cup1.show(); // 输出:这是塑料杯  AbstractFactory factory2 = new ClassicFlavorFactory();  MilkTea tea2 = factory2.createMilkTea();  Cup cup2 = factory2.createCup();  tea2.make(); // 输出:制作抹茶拿铁  cup2.show(); // 输出:这是陶瓷杯  // 如果热带风味奶茶店想要推出新口味的奶茶或新风格的杯子,// 只需要在自己的工厂类中添加新的实现  }  
}

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

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

相关文章

基于Python大数据的王者荣耀战队数据分析及可视化系统

作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…

IDEA开发工具使用技巧积累

一、IDEA 工具设置默认使用maven的settings.xml文件 第一步:打开idea工具,选中 File ——> New Projects Setup ——> Settings for New Projects 第二步:先设置下自动构建项目这个选项 第三步:选中 Build Tools ——>…

windows下pycharm社区版2024下载与安装(包含新建第一个工程)

windows下pycharm社区版2024下载与安装 下载pycharm pycharm官网 安装pycharm 1.进入官网 pycharm官网 下载 点击Download–>右侧Other versions 下载对应的社区版(如下图):下载网址 2.点击运行下载好的安装包 点击下一步 3.更改pychar…

2020款Macbook Pro A2251无法充电无法开机定位及修复

问题背景 up主有一台2020年的Macbook Pro,带Touch Bar,16G512G,四核I5,型号A2251 应该是一周没充电了,之前还用的好好的,后来有一天出差想带上 打开没电,手头上有个小米的66W快充头&#xff0c…

C#的自定义Tip窗体 - 开源研究系列文章

上次编写了自定义的提示和对话框窗体,这次记录的是自定义的Tip窗体,用于显示提示操作。有时间没编程了,这次就当进行了记录。 1、 项目目录; 2、 源码介绍; 1) 实现; 2) 应用; 3、 运行界面&…

Leetcode刷题笔记12

HJ1 字符串最后一个单词的长度 字符串最后一个单词的长度_牛客题霸_牛客网 这里可以使用rfind(),rfind()函数从字符串的末尾向前查找第一个空格的位置。这个空格将是最后一个单词和前面的单词的分隔符。首先使用getline读取字符串,然后用rfind找到最后一…

现在设备普遍切换成TYPE-C适配器后,一拖三数据线接口变革探析

随着科技的飞速发展,电子设备的接口标准也在不断地更新换代。近年来,TYPE-C接口凭借其高速传输、正反可插等显著优势,逐渐成为了众多电子设备的主流接口。从智能手机到平板电脑,从笔记本电脑到移动电源,TYPE-C接口的应…

Java-图书管理系统

我的个人主页 欢迎来到我的Java图书管理系统,接下来让我们一同探索如何书写图书管理系统吧! 1管理端和用户端 2建立相关的三个包(book、operation、user) 3建立程序入口Main类 4程序运行 1.首先图书馆管理系统分为管理员端和…

TPLCM柔性屏自动化贴合应用

在当前的显示屏制造领域,TP&LCM贴合技术是推动产品升级和满足市场需求的关键环节。随着技术的不断进步,全贴合技术因其卓越的显示效果和用户体验,逐渐成为中高端产品的标配。然而,这一技术的高精度要求和复杂工艺也带来了诸多…

物联网数据采集网关详细介绍-天拓四方

一、物联网数据采集网关的概述 物联网数据采集网关,简称数据采集网关,是物联网系统中的重要组成部分,位于物联网设备和云端平台之间。其主要职责是实现数据的采集、汇聚、转换、传输等功能,确保来自不同物联网设备的数据能够统一…

学习笔记——动态路由——OSPF(距离矢量协议)OSPF路由类型

OSPF路由类型 在OSPF中,路由类型指的是不同种类的路由,用于描述网络中不同的路由信息及其传输方式。 1、Intra Area路由(区域内路由) Intra Area路由(区域内路由/本地路由/内部路由)是OSPF协议中的一种路由类型,用于描述在同一个OSPF区域内…

小白直接冲!一区蛇群优化算法+双向深度学习+注意力机制!SO-BiTCN-BiGRU-Attention多输入单输出回归预测

小白直接冲!一区蛇群优化算法双向深度学习注意力机制!SO-BiTCN-BiGRU-Attention多输入单输出回归预测 目录 小白直接冲!一区蛇群优化算法双向深度学习注意力机制!SO-BiTCN-BiGRU-Attention多输入单输出回归预测预测效果基本介绍程…

Linux相关概念和易错知识点(16)(Shell原理、进程属性和环境变量表的联系)

Shell原理及其模拟实现 在认识进程exec系列函数、命令行参数列表、环境变量之后,我们可以尝试理解一下Shell的原理,将各方知识串联起来,让Shell跑起来才能真正理解这些概念。我会以模拟Shell执行的原理模拟一个Shell。途中配上相关讲解。 1…

Mybatis-03.入门-配置SQL提示

一.配置SQL提示 目前的Springboot框架在mybatis程序中编写sql语句并没有给到任何的提示信息,这对于开发者而言是很不友好的。因此我们需要配置SQL提示。 配置SQL提示 这样再去写SQL语句就会有提示了。 但是会发现指定表名时并没有给出提示。这是因为&#xff1a…

用kali入侵 DarkHole_2测试

进入kali系统调出root交互式界面 netdiscover -r 000.000.000.000/24 -------局域网探测IP工具 nmap 设备端口扫描 发现两个攻击点一个是80端口的Http 一个是22端口的ssh 发现有许多GIT文件 可能会出现git源码泄露 使用githack URL 命令还原git源文件 打开面板控制命令行 输入…

2024数学分析【南昌大学】

计算极限 lim ⁡ n → ∞ 2024 n ( 1 − cos ⁡ 1 n 2 ) n 3 1 + n 2 − n \mathop {\lim }\limits_{n \to \infty } \frac{{\sqrt[n]{{2024}}\left( {1 - \cos \frac{1}{{{n^2}}}} \right){n^3}}}{{\sqrt {1 + {n^2}} - n}} n→∞lim​1+n2 ​−nn2024 ​(1−cosn21​)n3​ …

【Vulnhub靶场】DC-4

DC-4靶场下载地址https://www.five86.com/downloads/DC-4.zip 本机IP:192.168.118.128 靶机IP:192.168.118.0/24 信息收集 扫描主机存活,扫描端口,扫描服务 第一步扫描出主机ip为192.168.118.141 nmap -sP 192.168.118.0/24 nm…

通过rancher2.7管理k8s1.24及1.24以上版本的k8s集群

目录 初始化实验环境 安装Rancher 登录Rancher平台 通过Rancher2.7管理已存在的k8s最新版集群 文档中的YAML文件配置直接复制粘贴可能存在格式错误,故实验中所需要的YAML文件以及本地包均打包至网盘. 链接:https://pan.baidu.com/s/1oYX4eGoBtW_R-7i…

canvas-editor首行缩进

canvas-editor中渲染部分的源码都在Draw.ts里,能找到computeRowList方法中并没有实现首行缩进相关的逻辑,但是实现了element.type ElementType.TAB的缩进,如图: 因此我们可以基于tab进行首行缩进的逻辑编写,在main.ts…

GoogleChrome和Edge浏览器闪屏问题

GoogleChrome和Edge浏览器闪屏问题 文章目录 GoogleChrome和Edge浏览器闪屏问题 买了电脑半年, GoogleChrome和edge浏览器出现了一个令人头疼的问题–闪屏, 就是打开这两个浏览器之后, 就会出现电脑屏幕一闪一闪的, 过一会就看不见了, 跟黑夜里的闪电一样, 遇到这种情况我都会直…