C++设计模式:桥接模式(Bridge)
什么是桥接模式?
桥接模式(Bridge Pattern)是一个用来解耦的设计模式,它将抽象层和实现层分离开,让它们可以独立变化。用最简单的话来说,就是让你能够改变抽象的功能和具体的实现,而不需要修改对方的代码。
举个例子,想象你在做一个图形绘制的程序,你有很多图形(比如圆形、方形),而且每种图形可能有不同的绘制方式(比如屏幕绘制、打印机绘制)。如果你把所有的图形和绘制方式都写在一起,每次你增加一种新的绘制方式或新图形时,你都要修改大量的代码,这样就会让系统变得很复杂。
桥接模式的思路是:把**图形(抽象)和绘制方式(实现)**分开,每一部分都可以独立变化,互不干扰。这样一来,增加新的图形或者新的绘制方式时,就不需要修改现有的代码,只需要扩展新的类即可。
桥接模式的结构
桥接模式有两个重要部分:
- 抽象部分(比如图形的类型,如圆形、方形等)
- 实现部分(比如具体的绘制方式,如屏幕绘制、打印绘制等)
这两个部分通过“桥”连接起来,形成了一个灵活可扩展的结构。下面的代码结构就能帮助你理解这一点。
桥接模式的代码示例
假设我们要实现一个图形绘制的程序,支持不同的图形(圆形、方形)和不同的绘制方式(屏幕绘制、打印机绘制)。我们来看看怎么用桥接模式来实现。
#include <iostream>
#include <string>// 绘图接口(实现类接口)
class DrawingAPI {
public:virtual void drawCircle(double x, double y, double radius) = 0;virtual ~DrawingAPI() = default;
};// 具体实现:屏幕绘制
class ScreenDrawingAPI : public DrawingAPI {
public:void drawCircle(double x, double y, double radius) override {std::cout << "在屏幕上绘制圆形,位置: (" << x << ", " << y << "), 半径: " << radius << std::endl;}
};// 具体实现:打印机绘制
class PrinterDrawingAPI : public DrawingAPI {
public:void drawCircle(double x, double y, double radius) override {std::cout << "在打印机上绘制圆形,位置: (" << x << ", " << y << "), 半径: " << radius << std::endl;}
};// 图形类(抽象类)
class Shape {
protected:DrawingAPI* drawingAPI; // 这里持有一个指向绘图实现类的指针public:Shape(DrawingAPI* api) : drawingAPI(api) {} // 通过构造函数注入具体实现类virtual void draw() = 0; // 绘制图形的接口virtual void resize(double factor) = 0; // 调整图形大小virtual ~Shape() = default;
};// 扩展的具体图形类:圆形
class Circle : public Shape {
private:double x, y, radius; // 圆形的坐标和半径public:Circle(double x, double y, double radius, DrawingAPI* api) : Shape(api), x(x), y(y), radius(radius) {}void draw() override {drawingAPI->drawCircle(x, y, radius); // 将绘制任务委托给具体实现}void resize(double factor) override {radius *= factor; // 调整圆形的半径}
};int main() {ScreenDrawingAPI screenAPI; // 创建屏幕绘制实现PrinterDrawingAPI printerAPI; // 创建打印机绘制实现// 创建圆形对象,使用不同的绘制方式Circle circle1(1, 2, 3, &screenAPI); // 在屏幕上绘制Circle circle2(5, 6, 4, &printerAPI); // 在打印机上绘制circle1.draw(); // 屏幕绘制圆形circle2.draw(); // 打印机绘制圆形circle1.resize(2.0); // 改变圆形大小circle1.draw(); // 再次绘制,使用屏幕绘制return 0;
}
代码讲解
让我们一步步来解读这段代码,看看桥接模式是如何工作的。
1. 绘图接口(DrawingAPI
)
class DrawingAPI {
public:virtual void drawCircle(double x, double y, double radius) = 0;virtual ~DrawingAPI() = default;
};
这个类定义了一个绘制圆形的方法 drawCircle
,它只是一个接口,并不做具体的绘制工作。任何具体的绘制方式(比如屏幕绘制、打印机绘制)都需要实现这个接口。
2. 具体的绘图实现(ScreenDrawingAPI
和 PrinterDrawingAPI
)
class ScreenDrawingAPI : public DrawingAPI {
public:void drawCircle(double x, double y, double radius) override {std::cout << "在屏幕上绘制圆形,位置: (" << x << ", " << y << "), 半径: " << radius << std::endl;}
};class PrinterDrawingAPI : public DrawingAPI {
public:void drawCircle(double x, double y, double radius) override {std::cout << "在打印机上绘制圆形,位置: (" << x << ", " << y << "), 半径: " << radius << std::endl;}
};
这两个类分别实现了 DrawingAPI
接口,提供了不同的绘制方式。ScreenDrawingAPI
在屏幕上绘制圆形,PrinterDrawingAPI
在打印机上绘制圆形。
3. 抽象类(Shape
)
class Shape {
protected:DrawingAPI* drawingAPI; // 持有一个绘图实现类的指针public:Shape(DrawingAPI* api) : drawingAPI(api) {} // 通过构造函数注入具体的绘图实现virtual void draw() = 0; // 绘制图形的接口virtual void resize(double factor) = 0; // 调整图形大小
};
Shape
是一个抽象类,它定义了所有图形的共同接口:draw()
和 resize()
。关键是它持有一个 DrawingAPI
的指针,这样它可以将具体的绘制任务委托给实现类。
4. 具体图形类(Circle
)
class Circle : public Shape {
private:double x, y, radius; // 圆形的坐标和半径public:Circle(double x, double y, double radius, DrawingAPI* api) : Shape(api), x(x), y(y), radius(radius) {}void draw() override {drawingAPI->drawCircle(x, y, radius); // 调用具体绘图实现的drawCircle方法}void resize(double factor) override {radius *= factor; // 改变圆形的半径}
};
Circle
类继承自 Shape
,并实现了 draw()
和 resize()
方法。它通过 drawingAPI
指针来调用具体的绘制方法,实现了与绘制方式的解耦。
5. 客户端代码
在 main
函数中,我们创建了两个 Circle
对象,分别使用了 ScreenDrawingAPI
和 PrinterDrawingAPI
作为绘制实现。通过调用 circle1.draw()
和 circle2.draw()
,我们可以看到两个不同的绘制方式。
int main() {ScreenDrawingAPI screenAPI; // 屏幕绘制实现PrinterDrawingAPI printerAPI; // 打印机绘制实现// 创建两个圆形对象,分别使用不同的绘制方式Circle circle1(1, 2, 3, &screenAPI);Circle circle2(5, 6, 4, &printerAPI);circle1.draw(); // 屏幕绘制圆形circle2.draw(); // 打印机绘制圆形circle1.resize(2.0); // 改变圆形大小circle1.draw(); // 再次绘制,使用屏幕绘制return 0;
}
总结
桥接模式的主要优点就是解耦
。我们把抽象部分(如图形类型)和实现部分(如绘制方式)分开,避免了两者之间的紧耦合。这样我们可以很方便地扩展新的图形类型或新的绘制方式,而不需要修改现有的代码。
比如,如果你以后需要支持新的绘制方式(比如在Web上绘制),你只需要实现一个新的 DrawingAPI
类,不用改动任何图形类;同样,如果你需要增加新的图形类型(比如矩形),只需要扩展 Shape
类,不需要改动任何绘制实现。
桥接模式适用于需要将抽象和实现分离,并且它们可能会独立变化的场景。
本文由mdnice多平台发布
相关文章:
C++设计模式:桥接模式(Bridge)
什么是桥接模式? 桥接模式(Bridge Pattern)是一个用来解耦的设计模式,它将抽象层和实现层分离开,让它们可以独立变化。用最简单的话来说,就是让你能够改变抽象的功能和具体的实现,而不需要修改…...
c++源码阅读__smart_ptr__正文阅读
文章目录 简介源码解析1. 引用计数的实现方式2. deleter静态方法的赋值时间节点3.make_smart的实现方式 与 好处4. 几种构造函数4.1 空构造函数4.2 接收指针的构造函数4.3 接收指针和删除方法的构造函数 , 以及auto进行模板lambda的编写4.4 拷贝构造函数4.5 赋值运算符 5. rele…...
halcon3D 1:1切片轮廓投影技术,透过像素距离,知实际物体的尺寸
首先说做个什么事儿 对一个物体的横截面进行1:1或者1:10的投影,也就是说世界物体1mm的话,投影到image中占1个或者10个像素值,这样,就可以透过直接计算image中的像素距离,知道实际物体的尺寸 用一张图说明是这样的。物…...
npm库xss依赖的使用方法和vue3 中Web富文本编辑器 wangeditor 使用xss库解决 XSS 攻击的方法
npm库xss依赖的使用方法和vue3 中Web富文本编辑器 wangeditor 使用xss库解决 XSS 攻击的方法 1. npm库xss依赖的使用方法1.1 xss库定义1.2 xss库功能 2. vue3 中 wangeditor 使用xss库解决 XSS 攻击的方法和示例2.1 在终端执行如下命令安装 xss 依赖2.2 在使用 wangeditor 的地…...
计算机网络 实验七 NAT配置实验
一、实验目的 通过本实验理解网络地址转换的原理和技术,掌握扩展NAT/NAPT设计、配置和测试。 二、实验原理 NAT配置实验的原理主要基于网络地址转换(NAT)技术,该技术用于将内部私有网络地址转换为外部公有网络地址,从…...
UI设计-色彩、层级、字体、边距(一)
一.色彩:色彩可以影响人的心理与行动,具有不同的象征意义;有冷暖,轻重,软硬等等。 1.色彩情绪:最直观的视觉感受 一个活动的页面所用的颜色必须要与其内容相适应,让人看起来舒服。有时我们会不…...
【网络安全】
黑客入侵 什么是黑客入侵? “黑客”是一个外来词,是英语单词hacker的中文音译。最初,“黑客”只是一个褒义词,指的是那些尽力挖掘计算机程序最大潜力的点脑精英,他们讨论软件黑客的技巧和态度,以及共享文化…...
c++趣味编程玩转物联网:基于树莓派Pico控制有源蜂鸣器
有源蜂鸣器是一种简单高效的声音输出设备,广泛应用于电子报警器、玩具、计时器等领域。在本项目中,我们结合树莓派Pico开发板,通过C代码控制有源蜂鸣器发出“滴滴”声,并解析其中涉及的关键技术点和硬件知识。 一、项目概述 1. 项…...
【MySQL】MySQL从入门到放弃
文章目录 声明MYSQL一,架构1.1.网络连接层数据库连接池 1.2.系统服务层1.2.1.SQL接口1.2.2.存储过程1.2.3.触发器1.2.4.解析器1.2.5.优化器1.2.6.缓存,缓冲 1.3.存储引擎层1.4.文件系统层1.4.1.日志模块1.4.2.数据模块 二,SQL 执行2.1.执行流程2.2.刷盘2.3.返回 三.库表设计3.1…...
redis-cluster集群搭建
集群节点信息 192.168.222.131:46379 主要节点1 192.168.222.131:46380 从节点1 192.168.222.131:46381 从节点2192.168.222.132:46379 主要节点2 192.168.222.132:46380 从节点1 192.168.222.132:46381 从节点2192.168.222.133:46379 主要节点3 192.168.222.133:46380 从节点…...
C语言解决空瓶换水问题:高效算法与实现
标题:C语言解决空瓶换水问题:高效算法与实现 一、问题描述 在一个饮料促销活动中,你可以通过空瓶换水的方式免费获得更多的水:3个空瓶可以换1瓶水。喝完这瓶水后,空瓶会再次变为空瓶。假设你最初拥有一定数量的空瓶&a…...
单例模式入门
单例模式是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。 它的运作方式是这样的: 如果你创建了一个对象, 同时过一会儿后你决定再创建一个新对象, 此时你会获得之前已创建的…...
MongoDB快速入门
1 MongoDB 1.1 MongoDB 概念 1.1.1 什么是 MongoDB MongoDB 是在2007年由DoubleClick公司的几位核心成员开发出的一款分布式文档数据库,由C语言编写。 目的是为了解决数据大量增长的时候系统的可扩展性和敏捷性。MongoDB要比传统的关系型数据库简单很多。 在Mo…...
c语言中的extern是什么
在C语言中,extern 是一个关键字,用于声明变量或函数的外部链接。它告诉编译器该变量或函数的定义在其他文件中,编译器在编译当前文件时并不需要知道变量或函数的具体定义,而是将它们视作外部引用。 1. 变量的 extern 声明 当你在…...
CTF之密码学(摩斯密码)
一、历史背景 摩尔斯电码发明于1837年,是一种早期的数字化通信形式。它最初由艾尔菲德维尔和摩尔斯等人构思,通过点、划和中间的停顿,把各个字元以及标点符号彼此独立地发送出去。这种标识不同符号的方案后来被放入摩尔斯的专利中࿰…...
Flink 任务启动脚本-V2(包括ck启动)
#!/bin/bash#crontab时设置,如果依赖其他环境变量配置,可以在脚本执行一下环境变量脚本 source /etc/profile# 进入脚本目录 curdirdirname "$0" curdircd "$curdir"; pwd echo "进入启动脚本目录 $curdir"# 定义应用程序…...
16:00面试,16:08就出来了,问的问题有点变态。。。
从小厂出来,没想到在另一家公司又寄了。 到这家公司开始上班,加班是每天必不可少的,看在钱给的比较多的份上,就不太计较了。没想到8月一纸通知,所有人不准加班,加班费不仅没有了,薪资还要降40%…...
selinux和防火墙
SElinux 1、selinux简介 SELinux是Security-Enhanced Linux的缩写,意思是安全强化的linux。 SELinux 主要由美国国家安全局(NSA)开发,当初开发的目的是为了避免资源的误用。 SELinux是对程序、文件等权限设置依据的一个内核模块。…...
Android 13 Aosp Settings Android Studio版本
Android 13 Aosp Settings Android Studio版本 Settings相关源码 Settings https://android.googlesource.com/platform/packages/apps/Settings/+/refs/heads/android13-release SettingsIntelligence https://android.googlesource.com/platform/packages/apps/SettingsIn…...
[241127] Mistral AI 更新 Le Chat,免费提供前沿 AI 助手!| TrendForce 预测 2025 十大科技趋势
目录 Mistral AI 更新 Le Chat,免费提供前沿 AI 助手!TrendForce 预测 2025 十大科技趋势 Mistral AI 更新 Le Chat,免费提供前沿 AI 助手! Mistral AI 宣布对其免费 AI 助手 Le Chat 进行重大更新,新增多项强大功能&…...
go-carbon v2.5.0 发布,轻量级、语义化、对开发者友好的 golang 时间处理库
carbon 是一个轻量级、语义化、对开发者友好的 Golang 时间处理库,提供了对时间穿越、时间差值、时间极值、时间判断、星座、星座、农历、儒略日 / 简化儒略日、波斯历 / 伊朗历的支持。 carbon 目前已捐赠给 dromara 开源组织,已被 awesome-go 收录&am…...
linux安全管理-账号口令
文章目录 1 设备密码复杂度策略2 设备密码生存周期、最小长度、更改最小间隔天数和过期前警告天数3 使用 PAM 认证禁止指定组之外的用户使用 su 切换到 root4 制作用户权限对照表 1 设备密码复杂度策略 1、配置内容 检查密码复杂度策略中设置的特殊字符、大写字母、小写字母和…...
uni-app自定义底部tab并且根据字段显示和隐藏
首先将所有tab使用到的页面创建好并且在pages里面配置好,要在pages.json中的"tabBar里面配置"custom": true将自带的tab底部导航关闭 "pages": [{"path": "pages/mine/mine","style": {"navigationBa…...
C#开发合集
用C#轻松搞定m3u8视频下载与合并 嘿,程序员们!今天咱们来聊聊如何用C#写个小程序,轻松下载和合并m3u8视频文件。没错,就是那种分段的流媒体视频。准备好了吗?让我们开始吧! 准备工作 在动手之前…...
Chrome和edge浏览器如何为任何网站强制暗模式
前言 因为我的编辑器是黑色,可能是看的时间长了比较喜欢这种颜色了,感觉白色有些刺眼。尤其是看文章时,两边的空白纯白色,所以强迫症搜素设置了谷歌浏览器和edge如何设置成黑色。 Chrome和edge浏览器如何为任何网站强制暗模式 前…...
第二十章 Java多线程--JUC并发工具-CountDownLatch
目录 一、CountDownLatch基础概念 CountDownLatch 的核心概念 CountDownLatch 的常用方法 场景一:主线程等待多个子线程执行完毕 场景二:实现多个线程同时开始执行任务 场景三:统计报表优化 CountDownLatch 的局限性 结论 二、Count…...
限制对 etcd 的访问范围是确保 Kubernetes 集群安全的一个重要环节。
限制对 etcd 的访问范围是确保 Kubernetes 集群安全的一个重要环节。通常,etcd 只应当对 Kubernetes 控制平面的组件(如 API Server、Controller Manager、Scheduler 等)以及某些维护工具(如备份工具)开放访问权限&…...
shell脚本基础学习_总结篇(完结)
细致观看可以,访问shell脚本学习专栏,对应章节会有配图https://blog.csdn.net/2201_75446043/category_12833287.html?spm1001.2014.3001.5482 导语 一、shell脚本简介 1. 定义: 2. 主要特点: 3. shell脚本的基本结构 4. S…...
Linux之网络基础
网络发展 网络的发展可以从人与人之间的工作模式开始谈起, 人与人的工作模式反应了机器与机器的工作模式: 1. 独立模式: 在网络发展的早期计算机间处于独立模式, 计算机之间相互独立 最开始计算机之间是独立运行的, 数据之间的交互需要人用软盘等存储介质拷贝过去, 一般涉及…...
《Vue零基础入门教程》第十课:属性绑定指令
往期内容 《Vue零基础入门教程》第一课:Vue简介 《Vue零基础入门教程》第二课:搭建开发环境 《Vue零基础入门教程》第三课:起步案例 《Vue零基础入门教程》第四课:应用实例 《Vue零基础入门教程》第五课:挂载 《…...
RabbitMQ 安装延迟队列插件 rabbitmq_delayed_message_exchange
前言: RabbitMQ 延迟队列插件(rabbitmq_delayed_message_exchange)是一个社区开发的插件,它为 RabbitMQ 添加了支持延迟消息的功能。通过这个插件,用户可以创建一种特殊的交换机类型 x-delayed-message,该…...
MATLAB中Simulink的基础知识
Simulink是MATLAB中的一种可视化仿真工具, 是一种基于MATLAB的框图设计环境,是实现动态系统建模、仿真和分析的一个软件包,被广泛应用于线性系统、非线性系统、数字控制及数字信号处理的建模和仿真中。 Simulink提供一个动态系统建模、仿真和…...
Swift——单例模式
单例是软件设计常用的一种模式,它的核心结构中只有一个被称为单例的特殊类,通过单例模式可以保证应用该模式的类只有一个实例化对象,其作用就是能够使类中的一个对象成为系统中的唯一实例。 单例的特点: 某个类只有一个实例化对象…...
百度智能云千帆大模型平台引领企业创新增长
本文整理自百度世界大会 2024——「智能跃迁 产业加速」论坛的同名演讲。 更多大会演讲内容,请访问: https://baiduworld.baidu.com 首先,跟大家分享一张图,这个是我们目前大模型应用落地的场景分布。可以看到,大模型…...
scala统计词频
目标:统计词频 (1)从文件1.tst,读入内容,保存在一个字符串中。 (2)统计字符串中,每个单词出现的频率 (3)对结果进行排序 (4)把最后…...
CTF之密码学(费纳姆密码)
一、作为二进制替换密码的费纳姆密码 定义:费纳姆密码是一种由二进制产生的替换密码,也被称为弗纳姆密码(Vernam cipher)。它采用二进制表示法,将明文转化为二进制数字,并通过与密钥进行模2加法运算来产生密…...
postgresql按照年月日统计历史数据
1.按照日 SELECT a.time,COALESCE(b.counts,0) as counts from ( SELECT to_char ( b, YYYY-MM-DD ) AS time FROM generate_series ( to_timestamp ( 2024-06-01, YYYY-MM-DD hh24:mi:ss ), to_timestamp ( 2024-06-30, YYYY-MM-DD hh24:mi:ss ), 1 days ) AS b GROUP BY tim…...
Python 网络爬虫进阶:动态网页爬取与反爬机制应对
在上一篇文章中,我们学习了如何使用 Python 构建一个基本的网络爬虫。然而,在实际应用中,许多网站使用动态内容加载或实现反爬机制来阻止未经授权的抓取。因此,本篇文章将深入探讨以下进阶主题: 如何处理动态加载的网…...
YOLOv11融合PIDNet中的PagFM模块及相关改进思路
YOLOv11v10v8使用教程: YOLOv11入门到入土使用教程 YOLOv11改进汇总贴:YOLOv11及自研模型更新汇总 《PIDNet: A Real-time Semantic Segmentation Network Inspired by PID Controllers》 一、 模块介绍 论文链接:https://arxiv.org/pdf/2…...
使用Python实现自动化邮件通知:当长时程序运行结束时
使用Python实现自动化邮件通知:当长时程序运行结束时 前提声明 本代码仅供学习和研究使用,不得用于商业用途。请确保在合法合规的前提下使用本代码。 目录 引言项目背景项目设置代码分析 导入所需模块定义邮件发送函数发送邮件 实现步骤结语全部代码…...
smb cifs samba smbpasswd 笔记241127
smb cifs samba smbpasswd 笔记241127 SMB、CIFS和Samba都是与文件共享相关的技术,它们在不同的层面上发挥着作用。以下是关于SMB、CIFS和Samba的详细解释: SMB(Server Message Block) 定义:SMB(Server …...
Spring MVC练习(前后端分离开发实例)
White graces:个人主页 🙉专栏推荐:Java入门知识🙉 🐹今日诗词:二十五弦弹夜月,不胜清怨却飞来🐹 ⛳️点赞 ☀️收藏⭐️关注💬卑微小博主🙏 ⛳️点赞 ☀️收藏⭐️关注Ǵ…...
使用 pycharm 新建不使用 python 虚拟环境( venv、conda )的工程
有时候我们发现一个好玩的 demo,想赶快在电脑上 pip install 一下跑起来,发现因为 python 的 venv、conda 环境还挺费劲的,因为随着时间的发展,之前记得很清楚的 venv、conda 的用法,不经常使用,半天跑不起…...
英语知识网站开发:Spring Boot框架应用
3系统分析 3.1可行性分析 通过对本英语知识应用网站实行的目的初步调查和分析,提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本英语知识应用网站采用SSM框架,JAVA作为开发语…...
Pandas 数据读取与导出
Pandas 是一个强大的 Python 库,用于数据处理和分析。它提供了许多函数来读取和导入数据,支持多种文件格式,如 CSV、Excel、SQL 数据库、JSON 等。以下是一些常用的数据读取和导出方法: 常用方法 格式文件格式读取函数写入&…...
Day49 | 动态规划 :线性DP 判断子序列两个字符串的删除操作
Day49 | 动态规划 :线性DP 判断子序列&&两个字符串的删除操作 动态规划应该如何学习?-CSDN博客 动态规划学习: 1.思考回溯法(深度优先遍历)怎么写 注意要画树形结构图 2.转成记忆化搜索 看哪些地方是重复…...
HDR视频技术之三:色度学与颜色空间
HDR 技术的第二个理论基础是色度学。从前面的内容中可以了解到,光学以及人类视觉感知模型为人类提供了解释与分析人类感知亮度的理论基础,但是 HDR 技术不仅仅关注于提升图像与视频的亮度范围,同时也关注于提供更加丰富的色彩。因此ÿ…...
nginx和netcore加载常见的3D模型
背景 数字孪生带火了3D版的Web世界,3D模型格式也是众多,常见的glb适合web传输,fbx,gltf,obj,unity等常用于模型编辑和处理。我们在用netcore或者wasm加载这些3D模型文件时,一般都需要手工增加M…...
ABAP开发学习——标准GUI状态模板的复制
补充一下创建了GUI状态后复制标准状态的方法 首先创建GUI状态 此时按钮全部都是空的 点击顶部的附加-调整模板 选择列表查看器 应用成功,下一步点击激活即可 另外需要注意,功能键中的三个图标的代码并不是习惯性写的”BACK、EXIT、CANCEL",在这个标…...
酷!用豆包MarsCode 写了一个五子棋小游戏
作者:一起重学前端 前言 2017 年,当时大学三本毕业前端工作一年,去深圳找工作面试,在拉勾上海投,接到某公司前端开发团队回复询问邮箱账号,喜滋滋的以为可以有面试了。一看邮箱,抛给我一道面试…...