瑞_23种设计模式_抽象工厂模式

文章目录

    • 1 抽象工厂模式(Abstract Factory Pattern)
      • 1.1 概念
      • 1.2 介绍
      • 1.3 小结
      • 1.4 结构
    • 2 案例一
      • 2.1 案例需求
      • 2.2 代码实现
    • 3 案例二
      • 3.1 需求
      • 3.2 实现
    • 4 总结
      • 4.1 抽象工厂模式优缺点
      • 4.2 抽象工厂模式使用场景
      • 4.3 抽象工厂模式VS工厂方法模式
      • 4.4 抽象工厂模式VS建造者模式

🙊 前言:本文章为瑞_系列专栏之《23种设计模式》的抽象工厂模式篇。本文中的部分图和概念等资料,来源于博主学习设计模式的相关网站《菜鸟教程 | 设计模式》和《黑马程序员Java设计模式详解》,特此注明。本文中涉及到的软件设计模式的概念、背景、优点、分类、以及UML图的基本知识和设计模式的6大法则等知识,建议阅读 《瑞_23种设计模式_概述》

本系列-设计模式-链接:《瑞_23种设计模式_概述》
本系列-单例模式-链接:《瑞_23种设计模式_单例模式》
本系列-工厂模式-链接:《瑞_23种设计模式_工厂模式》
本系列-原型模式-链接:《瑞_23种设计模式_原型模式》

在这里插入图片描述

1 抽象工厂模式(Abstract Factory Pattern)

1.1 概念

  抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

  在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

  抽象工厂模式提供了一种创建一系列相关或相互依赖对象的接口,而无需指定具体实现类。通过使用抽象工厂模式,可以将客户端与具体产品的创建过程解耦,使得客户端可以通过工厂接口来创建一族产品。

  抽象工厂模式与工厂方法模式不同,工厂方法模式中考虑的是一类产品的生产,这些工厂只生产同种类产品,同种类产品称为同等级产品,也就是说:工厂方法模式只考虑生产同等级的产品,但是在现实生活中许多工厂是综合型的工厂,能生产多等级(种类) 的产品,如电器厂既生产电视机又生产洗衣机或空调,大学既有软件专业又有生物专业等。

1.2 介绍

  • 意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

  • 主要解决:主要解决接口选择的问题。

  • 何时使用:系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。

  • 如何解决:在一个产品族里面,定义多个产品。

  • 关键代码:在一个工厂里聚合多个同类产品。

  • 应用实例:工作了,为了参加一些聚会,肯定有两套或多套衣服吧,比如说有商务装(成套,一系列具体产品)、时尚装(成套,一系列具体产品),甚至对于一个家庭来说,可能有商务女装、商务男装、时尚女装、时尚男装,这些也都是成套的,即一系列具体产品。假设一种情况(现实中是不存在的,但有利于说明抽象工厂模式),在您的家中,某一个衣柜(具体工厂)只能存放某一种这样的衣服(成套,一系列具体产品),每次拿这种成套的衣服时也自然要从这个衣柜中取出了。用 OOP 的思想去理解,所有的衣柜(具体工厂)都是衣柜类的(抽象工厂)某一个,而每一件成套的衣服又包括具体的上衣(某一具体产品),裤子(某一具体产品),这些具体的上衣其实也都是上衣(抽象产品),具体的裤子也都是裤子(另一个抽象产品)。

  • 优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。

  • 缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。

  • 使用场景
      1️⃣ QQ 换皮肤,一整套一起换。
      2️⃣ 生成不同操作系统的程序。

  • 注意事项:产品族难扩展,产品等级易扩展。

  抽象工厂模式通常涉及一族相关的产品,每个具体工厂类负责创建该族中的具体产品。客户端通过使用抽象工厂接口来创建产品对象,而不需要直接使用具体产品的实现类。

1.3 小结

  是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。

  抽象工厂模式是工厂方法模式的升级版,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品

  本文要介绍的抽象工厂模式将考虑多等级产品的生产,将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族,下图所示横轴是产品等级,也就是同一类产品;纵轴是产品族,也就是同一品牌的产品,同一品牌的产品产自同一个工厂。

在这里插入图片描述

1.4 结构

  抽象工厂模式的主要角色如下:
    1️⃣ 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品。
    2️⃣ 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
    3️⃣ 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
    4️⃣ 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它 同具体工厂之间是多对一的关系。

2 案例一

2.1 案例需求

  现有一家咖啡店,要生产咖啡还要生产甜点,如提拉米苏、抹茶慕斯等,要是按照工厂方法模式,需要定义提拉米苏类、抹茶慕斯类、提拉米苏工厂、抹茶慕斯工厂、甜点工厂类,很容易发生类爆炸情况。其中拿铁咖啡、美式咖啡是一个产品等级,都是咖啡;提拉米苏、抹茶慕斯也是一个产品等级;拿铁咖啡和提拉米苏是同一产品族(也就是都属于意大利风味),美式咖啡和抹茶慕斯是同一产品族(也就是都属于美式风味)。

  这个案例使用抽象工厂模式实现的类图如下:

在这里插入图片描述

2.2 代码实现

抽象工厂(接口)
/*** 抽象工厂** @author LiaoYuXing-Ray**/
public interface DessertFactory {// 生产咖啡的功能Coffee createCoffee();// 生产甜品的功能Dessert createDessert();
}
咖啡(抽象类)
/*** 咖啡抽象类** @author LiaoYuXing-Ray**/
public abstract class Coffee {public abstract String getName();// 加糖public void addSugar() {System.out.println("加糖");}// 加奶public void addMilk() {System.out.println("加奶");}
}
甜品(抽象类)
/*** 甜品抽象类** @author LiaoYuXing-Ray**/
public abstract class Dessert {public abstract void show();
}
美式风味的甜品工厂(类)
/*** 美式风味的甜品工厂* - 生产美式咖啡和抹茶慕斯** @author LiaoYuXing-Ray**/
public class AmericanDessertFactory implements DessertFactory {public Coffee createCoffee() {return new AmericanCoffee();}public Dessert createDessert() {return new MatchaMousse();}
}
意大利风味甜品工厂(类)
/*** 意大利风味甜品工厂* - 生产拿铁咖啡和提拉米苏甜品** @author LiaoYuXing-Ray**/
public class ItalyDessertFactory implements DessertFactory {public Coffee createCoffee() {return new LatteCoffee();}public Dessert createDessert() {return new Tiramisu();}
}
美式咖啡(类)
/*** 美式咖啡** @author LiaoYuXing-Ray**/
public class AmericanCoffee extends Coffee {public String getName() {return "美式咖啡";}
}
拿铁咖啡(类)
/*** 拿铁咖啡** @author LiaoYuXing-Ray**/
public class LatteCoffee extends Coffee {public String getName() {return "拿铁咖啡";}
}
抹茶慕斯(类)
/*** 抹茶慕斯类** @author LiaoYuXing-Ray**/
public class MatchaMousse extends Dessert {@Overridepublic void show() {System.out.println("抹茶慕斯");}
}
提拉米苏(类)
/*** 提拉米苏类** @author LiaoYuXing-Ray**/
public class Tiramisu extends Dessert {@Overridepublic void show() {System.out.println("提拉米苏");}
}
测试类
/*** 测试类** @author LiaoYuXing-Ray**/
public class Client {public static void main(String[] args) {// 创建的是意大利风味甜品工厂对象
//         ItalyDessertFactory factory = new ItalyDessertFactory();AmericanDessertFactory factory = new AmericanDessertFactory();// 获取拿铁咖啡和提拉米苏甜品Coffee coffee = factory.createCoffee();Dessert dessert = factory.createDessert();System.out.println(coffee.getName());dessert.show();}
}

瑞:该案例实现使用抽象工厂模式,如果要加同一个产品族的话,只需要再加一个对应的工厂类即可,不需要修改其他的类。

3 案例二

本案例为菜鸟教程中的案例

3.1 需求

  我们将创建 Shape 和 Color 接口和实现这些接口的实体类。下一步是创建抽象工厂类 AbstractFactory。接着定义工厂类 ShapeFactory 和 ColorFactory,这两个工厂类都是扩展了 AbstractFactory。然后创建一个工厂创造器/生成器类 FactoryProducer。

  AbstractFactoryPatternDemo 类使用 FactoryProducer 来获取 AbstractFactory 对象。它将向 AbstractFactory 传递形状信息 Shape(CIRCLE / RECTANGLE / SQUARE),以便获取它所需对象的类型。同时它还向 AbstractFactory 传递颜色信息 Color(RED / GREEN / BLUE),以便获取它所需对象的类型。

  类图如下:

在这里插入图片描述

3.2 实现

步骤1
  为形状创建一个接口。

Shape.java
public interface Shape {void draw();
}

步骤2
  创建实现接口的实体类。

Rectangle.java
public class Rectangle implements Shape {@Overridepublic void draw() {System.out.println("Inside Rectangle::draw() method.");}
}
Square.java
public class Square implements Shape {@Overridepublic void draw() {System.out.println("Inside Square::draw() method.");}
}
Circle.java
public class Circle implements Shape {@Overridepublic void draw() {System.out.println("Inside Circle::draw() method.");}
}

步骤3
  为颜色创建一个接口。

Color.java
public interface Color {void fill();
}

步骤4

  创建实现接口的实体类。

Red.java
public class Red implements Color {@Overridepublic void fill() {System.out.println("Inside Red::fill() method.");}
}
Green.java
public class Green implements Color {@Overridepublic void fill() {System.out.println("Inside Green::fill() method.");}
}
Blue.java
public class Blue implements Color {@Overridepublic void fill() {System.out.println("Inside Blue::fill() method.");}
}

步骤5
  为 Color 和 Shape 对象创建抽象类来获取工厂。

AbstractFactory.java
public abstract class AbstractFactory {public abstract Color getColor(String color);public abstract Shape getShape(String shape);
}

步骤6
  创建扩展了 AbstractFactory 的工厂类,基于给定的信息生成实体类的对象。

ShapeFactory.java
public class ShapeFactory extends AbstractFactory {@Overridepublic Shape getShape(String shapeType){if(shapeType == null){return null;}        if(shapeType.equalsIgnoreCase("CIRCLE")){return new Circle();} else if(shapeType.equalsIgnoreCase("RECTANGLE")){return new Rectangle();} else if(shapeType.equalsIgnoreCase("SQUARE")){return new Square();}return null;}@Overridepublic Color getColor(String color) {return null;}
}
ColorFactory.java
public class ColorFactory extends AbstractFactory {@Overridepublic Shape getShape(String shapeType){return null;}@Overridepublic Color getColor(String color) {if(color == null){return null;}        if(color.equalsIgnoreCase("RED")){return new Red();} else if(color.equalsIgnoreCase("GREEN")){return new Green();} else if(color.equalsIgnoreCase("BLUE")){return new Blue();}return null;}
}

步骤7
  创建一个工厂创造器/生成器类,通过传递形状或颜色信息来获取工厂。

FactoryProducer.java
public class FactoryProducer {public static AbstractFactory getFactory(String choice){if(choice.equalsIgnoreCase("SHAPE")){return new ShapeFactory();} else if(choice.equalsIgnoreCase("COLOR")){return new ColorFactory();}return null;}
}

步骤8
  使用 FactoryProducer 来获取 AbstractFactory,通过传递类型信息来获取实体类的对象。

AbstractFactoryPatternDemo.java
public class AbstractFactoryPatternDemo {public static void main(String[] args) {//获取形状工厂AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");//获取形状为 Circle 的对象Shape shape1 = shapeFactory.getShape("CIRCLE");//调用 Circle 的 draw 方法shape1.draw();//获取形状为 Rectangle 的对象Shape shape2 = shapeFactory.getShape("RECTANGLE");//调用 Rectangle 的 draw 方法shape2.draw();//获取形状为 Square 的对象Shape shape3 = shapeFactory.getShape("SQUARE");//调用 Square 的 draw 方法shape3.draw();//获取颜色工厂AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");//获取颜色为 Red 的对象Color color1 = colorFactory.getColor("RED");//调用 Red 的 fill 方法color1.fill();//获取颜色为 Green 的对象Color color2 = colorFactory.getColor("GREEN");//调用 Green 的 fill 方法color2.fill();//获取颜色为 Blue 的对象Color color3 = colorFactory.getColor("BLUE");//调用 Blue 的 fill 方法color3.fill();}
}

步骤9
  执行程序,输出结果:

	Inside Circle::draw() method.Inside Rectangle::draw() method.Inside Square::draw() method.Inside Red::fill() method.Inside Green::fill() method.Inside Blue::fill() method.

4 总结

4.1 抽象工厂模式优缺点

  • 优点

  1️⃣ 解耦:抽象工厂模式有助于降低客户端与具体实现之间的耦合度,从而提高系统的可扩展性和可维护性。
  2️⃣ 灵活性:抽象工厂模式使得系统更加灵活,可以轻松地添加或删除产品族,而无需修改客户端代码。
  3️⃣ 易于测试:由于具体实现与客户端代码的解耦,使得测试变得更加容易,可以更容易地模拟和验证各种不同的工厂实现。
  4️⃣ 多等级产品:抽象工厂模式可以支持多等级的产品,每个等级可以有自己的工厂实现,从而实现更细粒度的控制和配置。

  当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象

  • 缺点

  1️⃣ 代码复杂度增加:使用抽象工厂模式需要编写更多的代码和接口,这可能会增加代码的复杂度和开发时间。
  2️⃣ 违反开闭原则:在抽象工厂模式中,如果要添加一个新的产品族,需要修改抽象工厂接口及其所有子类,这违反了开闭原则(即软件实体应该对扩展开放,对修改封闭)。
  3️⃣ 过度抽象:抽象工厂模式可能会导致过度抽象,使得系统变得更加复杂和难以理解。
  4️⃣ 具体实现依赖:如果具体实现依赖于抽象工厂,那么它们之间的耦合度仍然很高,这可能会限制系统的灵活性和可维护性。

  当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改

4.2 抽象工厂模式使用场景

  • 当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空调等。
  • 系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。
  • 系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构。

  如:输入法换皮肤,一整套一起换。生成不同操作系统的程序。

4.3 抽象工厂模式VS工厂方法模式

  抽象工厂模式是工厂方法模式的升级版,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。

4.4 抽象工厂模式VS建造者模式

  抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品:具有不同分类维度的产品组合,采用抽象工厂模式则是不需要关心构建过程,只关心什么产品由什么工厂生产即可。
  建造者模式则是要求按照指定的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新产品。
  如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族的产品,那么建造者模式就是一个汽车组装工厂,通过对部件的组装可以返回一辆完整的汽车。




本文是博主的粗浅理解,可能存在一些错误或不完善之处,如有遗漏或错误欢迎各位补充,谢谢

  如果觉得这篇文章对您有所帮助的话,请动动小手点波关注💗,你的点赞👍收藏⭐️转发🔗评论📝都是对博主最好的支持~


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

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

相关文章

node.js基础--01

Author nodes:(题记) node.js is an open-source,cross-platform JAVAScript runtime environment。 node.js是一个开源,跨平台的js运行环境 common commands(常用指令) 1、C: enter hard …

javaScript的序列化与反序列化

render函数的基本实现 javaScript的序列化与反序列化 一,js中的序列化二,序列化三,反序列化四,总结 一,js中的序列化 js中序列化就是对象转换成json格式的字符串,使用JSON对象的stringify方法,…

新书速览|Python数据科学应用从入门到精通

系统教授数据科学与Python实战,涵盖线性回归、逻辑回归、决策树、随机森林、神经网 本书内容 随着数据存储、数据处理等大数据技术的快速发展,数据科学在各行各业得到广泛的应用。数据清洗、特征工程、数据可视化、数据挖掘与建模等已成为高校师生和职场…

STL——空间配置器

空间配置器是STL六大组件之一,它和其他五个组件相互配合,起着很关键的作用。 容器:各种数据结构、如vector、list、stack、deque、queue、set、map、unordered_map等等算法:各种算法,如sort、serach、copy、erase 提供…

C#用正则表达式验证格式:电话号码、密码、邮编、手机号码、身份证、指定的小数点后位数、有效月、有效日

正则表达式在程序设计中有着重要的位置,经常被用于处理字符串信息。 用Regex类的IsMatch方法,使用正则表达式可以验证电话号码是否合法。 一、涉及到的知识点 Regex类的IsMatch方法用于指示正则表达式使用pattern参数中指定的正则表达式是否在输入字符串…

计算机网络_1.6.2 计算机网络体系结构分层的必要性

1.6.2 计算机网络体系结构分层的必要性 一、五层原理体系结构每层各自主要解决什么问题1、物理层2、数据链路层3、网络层4、运输层5、应用层 二、总结三、练习 笔记来源: B站 《深入浅出计算机网络》课程 本节主要介绍实现计算机网络需要解决哪些问题?以…

这种学习单片机的顺序是否合理?

这种学习单片机的顺序是否合理? 在开始前我有一些资料,是我根据网友给的问题精心整理了一份「单片机的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!&#xff01…

随着网络的快速发展,网络安全问题也日益凸显,遇到攻击该如何处理,如何抉择合适的防护方案

DexunCloud 经过研究发现当今世界,随着网络的快速发展,网络安全问题也日益凸显。其中,DDoS(分布式拒绝服务)攻击被认为是网络安全领域里最为严重的威胁之一。毫无疑问,DDoS攻击不仅可以导致网络服务中断&am…

支付宝直连商户处理支付交易投诉管理,支持多商户

大家好,我是小悟 1、问题背景 玩过支付宝生态的,或许就有这种感受,如果收到投诉单,不会通知到手机端,只会在支付宝商家后台-账号中心-安全中心-消费者投诉-支付交易投诉那里显示。那你能一直盯着电脑看吗?…

Flink CEP(基本概念)

Flink CEP 在Flink的学习过程中,我们已经掌握了从基本原理和核心层的DataStream API到底层的处理函数,再到应用层的Table API和SQL的各种手段,可以应对实际应用开发的各种需求。然而,在实际应用中,还有一类更为复…

AI Partition(银灿U盘分区工具)V2.0.0.3

AI Partition(银灿U盘分区工具)V2.0.0.3.zip 复制链接下载吧 https://url20.ctfile.com/f/36743220-1017367709-67f1b9?p2024 (访问密码: 2024) 支持IS903B IS902E IS916 AI Partition(银灿U盘分区量产工具) 这个是银灿官方发布的最新版U盘分区工具,版本号V2.0.0…

翻转二叉树

226. 翻转二叉树 已解答 简单 相关标签 相关企业 给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。 示例 1: 输入:root [4,2,7,1,3,6,9] 输出:[4,7,2,9,6,3,1]示例 2: 输入&#xff1a…

从零学习Linux操作系统 第二十五部分 文本处理工具

一、grep命令的基本使用方法及常用参数介绍 grep [全称&#xff1a;Globally search a Regular Expression and Print 全局搜索正则表达式并打印 ] grep 命令格式 grep 匹配条件 处理文件 grep root passwd过滤root关键字grep -i root passwd后略大小写grep -E “<root”…

嵌入式中物联网核心技术有哪些

IoT军事技术 物联网军事技术是一项利用IoT感知技术在军事活动中获取人、装备、作战环境状态的信息特征&#xff0c;从而实现在军事活动中做出智能化决策和控制局势的军事方针。 据悉&#xff0c;早于2012年10月军方联合了社会研究机构合力创建了“军事物联网联合实验室”。 …

C++核心deque容器,stack容器,queue容器,list容器,set容器,pair ,map容器

3.deque容器 1.deque容器的基本概念 Vector容器是单向开口的连续内存空间&#xff0c;deque则是一种双向开口的连续线性空间。所谓的双向开口&#xff0c;意思是可以在头尾两端插入元素&#xff0c;但是在其头部操作效率奇差&#xff0c;无法被接受。 deque容器和vector容器最…

C++类和对象入门(二)

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、类的作用域 类定义了一个新的作用域&#xff0c;类的所有成员都在类的作用域中。在类体外定义成员时&#xff0c;需要…

vue3快速入门

文章目录 1. Vue3简介1.1. 性能的提升1.2.源码的升级1.3. 拥抱TypeScript1.4. 新的特性 2. 创建Vue3工程2.1. 基于 vue-cli 创建2.2. 基于 vite 创建&#xff08;推荐&#xff09;vite介绍创建步骤项目结构安装插件项目结构总结 2.3. 一个简单的效果Person.vueApp.vue 3. Vue3核…

关于爬取所有哔哩哔哩、任意图片、所有音乐、的python脚本语言-Edge浏览器插件 全是干货!

这些都是现成的并且实时更新的&#xff01;从次解放双手&#xff01; 首先有自己的edge浏览器基本上都有并且找到插件选项 1.哔哩哔哩视频下载助手&#xff08;爬取哔哩哔哩视频&#xff09; bilibili哔哩哔哩视频下载助手 - Microsoft Edge Addons 下面是效果&#xff1a; 2.图…

2024年数学建模美赛 A~E 题目解析

2024美赛A题&#xff1a;资源可用性和性别比例 背景 尽管一些动物物种不属于通常的雄性或雌性&#xff0c;大多数物种在出生时要么显著地为雄性&#xff0c;要么为雌性。虽然许多物种在出生时表现出1:1的性别比&#xff0c;但其他物种则偏离了这个均衡的性别比例。这被称为性…

PostgreSQL 也很强大,为何在中国大陆,MySQL 成为主流,PostgreSQL 屈居二线呢?

问题&#xff1a; PostgreSQL 也很强大&#xff0c;为何在中国大陆&#xff0c;MySQL 成为主流&#xff0c;PostgreSQL 屈居二线呢&#xff1f;PostgreSQL 能否替代 MySQL&#xff1f; 当我们讨论为何 MySQL 在中国大陆成为主流而 PostgreSQL 屈居二线时&#xff0c; 我们其实…