16k面试中的10个问题
你好,我是田哥
节前,有位朋友跟我反馈面试中一些问题,这位朋友的基本情况:
坐标:上海,年限:3年不到,期望薪资;16k
下面我们来看看具体问题:
01:请解释注解和反射在Java中的作用
在Java中,注解(Annotation)和反射(Reflection)是两个重要的特性,它们分别用于在代码中添加元数据和动态地操作类、对象和方法。
注解是一种用于向代码中添加元数据的方式。通过在代码中使用注解,我们可以为类、方法、字段等元素添加额外的信息,这些信息可以被编译器、工具或运行时环境读取和利用。注解可以用于标记代码的特性、指示编译器生成额外的代码、配置工具的行为等。Java中的一些常见注解包括 @Override、@Deprecated、@SuppressWarnings等。注解的作用是提供了一种机制,使得我们可以在代码中添加额外的信息,从而实现更灵活、更高效的编程。
反射是Java中的一种机制,它允许程序在运行时动态地获取类的信息、创建对象、调用方法等。通过反射,我们可以在运行时检查类的属性和方法,获取类的构造器、字段和方法等信息,并且可以在运行时动态地创建对象、调用方法,甚至可以修改私有字段的值。反射的作用是使得程序具有更大的灵活性和扩展性,可以在运行时根据需要动态地操作类和对象。
总结起来,注解和反射在Java中的作用如下:
注解用于向代码中添加元数据,提供了一种机制来标记代码的特性、指示编译器生成额外的代码、配置工具的行为等。
反射允许程序在运行时动态地获取类的信息、创建对象、调用方法等,提供了一种机制来在运行时动态地操作类和对象。
02:在项目中多线程问题是如何解决的?
在多线程编程中,同步问题是指多个线程访问共享资源时可能出现的数据不一致或冲突的情况。为了解决同步问题,可以采用以下几种常见的同步机制:
互斥锁(Mutex):通过互斥锁来保护共享资源,一次只允许一个线程访问该资源。当一个线程获取到互斥锁后,其他线程需要等待该线程释放锁才能访问资源。
信号量(Semaphore):通过信号量来控制对共享资源的访问数量。信号量维护一个计数器,当计数器大于0时,线程可以访问资源;当计数器为0时,线程需要等待其他线程释放资源后才能访问。
条件变量(Condition):通过条件变量来实现线程间的通信和协调。条件变量可以让线程在某个条件满足时等待,直到其他线程通知条件满足后再继续执行。
读写锁(ReadWrite Lock):适用于读多写少的场景,读写锁允许多个线程同时读取共享资源,但只允许一个线程写入共享资源。
原子操作(Atomic Operation):原子操作是指不可被中断的操作,可以保证操作的完整性。在多线程编程中,可以使用原子操作来保证对共享资源的操作是原子的,从而避免数据不一致的问题。
以上是常见的同步机制,根据具体的场景和需求选择合适的同步机制来解决多线程中的同步问题。
03:Redis和Zookeeper实现分布式锁,哪个更好?
Redis和Zookeeper都可以用来实现分布式锁,但它们有不同的特点和适用场景。
Redis是一个高性能的内存数据库,支持多种数据结构和丰富的功能。它的分布式锁是基于Redis的原子操作(如SETNX、EXPIRE等)实现的。Redis分布式锁的优点是简单易用,实现起来比较容易,而且性能较高。但是,Redis的分布式锁在某些情况下可能存在问题,比如在网络分区或节点故障的情况下可能会出现锁失效或死锁的问题。
Zookeeper是一个分布式协调服务,提供了高可用、一致性和可靠性的分布式锁实现。Zookeeper的分布式锁是基于临时有序节点(EPHEMERAL_SEQUENTIAL)实现的。Zookeeper分布式锁的优点是具有强一致性和可靠性,可以有效地解决网络分区和节点故障的问题。但是,Zookeeper的分布式锁实现相对复杂,需要依赖Zookeeper集群,并且性能相对较低。
综上所述,选择Redis还是Zookeeper实现分布式锁,需要根据具体的场景和需求来决定。如果对性能要求较高,且可以容忍一定的风险,可以选择Redis。如果对一致性和可靠性要求较高,且可以接受一定的性能损耗,可以选择Zookeeper。
04:你对Spring Cloud微服务框架的理解是什么?
Spring Cloud是一个基于Spring Boot的微服务框架,它提供了一系列的工具和组件,用于简化微服务架构的开发和部署。Spring Cloud提供了服务注册与发现、负载均衡、断路器、分布式配置、消息总线等功能,帮助开发者构建弹性、可靠、可扩展的分布式系统。
通过Spring Cloud,开发者可以将一个大型的应用系统拆分成多个小的、自治的服务,每个服务都可以独立开发、部署和扩展。这种微服务架构的好处是可以提高系统的可维护性、可扩展性和可测试性,同时也能够更好地应对复杂性和变化性。
Spring Cloud提供了多个核心组件,如Eureka、Ribbon、Hystrix、Config等,这些组件可以灵活地组合使用,根据实际需求来构建自己的微服务架构。同时,Spring Cloud还与其他开源项目(如Netflix OSS)进行了集成,提供了更多的功能和选项。
总之,Spring Cloud是一个强大而灵活的微服务框架,它为开发者提供了丰富的工具和组件,帮助构建高效、可靠的分布式系统。
05:MySQL数据库,能够谈谈事务的ACID属性和隔离级别吗?ACID实现原理是什么?
当谈到MySQL数据库中的事务时,我们可以讨论事务的ACID属性和隔离级别。
ACID属性是指事务应具备的四个特性,包括原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。
原子性(Atomicity):事务是一个不可分割的操作单元,要么全部执行成功,要么全部失败回滚。如果事务中的任何一个操作失败,整个事务都会被回滚到事务开始前的状态,保证数据的完整性。
一致性(Consistency):事务执行前后,数据库的状态必须保持一致。事务的执行不会破坏数据库的完整性约束,如主键、外键等。
隔离性(Isolation):多个事务并发执行时,每个事务的操作都应该与其他事务的操作相互隔离,互不干扰。事务的隔离级别可以通过设置来控制,常见的隔离级别有读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable)。
持久性(Durability):一旦事务提交成功,对数据库的修改就是永久性的,即使系统发生故障或重启,修改的数据也不会丢失。
隔离级别是指多个事务并发执行时,事务之间的隔离程度。MySQL数据库支持四个隔离级别,分别是读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable)。
读未提交(Read Uncommitted):最低的隔离级别,事务可以读取其他事务未提交的数据,可能会导致脏读、不可重复读和幻读的问题。
读已提交(Read Committed):事务只能读取其他事务已提交的数据,可以避免脏读问题,但仍可能出现不可重复读和幻读的问题。
可重复读(Repeatable Read):事务在执行期间看到的数据保持一致,即使其他事务对数据进行了修改,也不会影响当前事务的读取操作。可以避免脏读和不可重复读问题,但仍可能出现幻读问题。MySQL的默认隔离级别。
串行化(Serializable):最高的隔离级别,事务串行执行,可以避免脏读、不可重复读和幻读的问题,但会降低并发性能。
具体来说,MySQL使用了两种类型的日志:重做日志(Redo Log)和回滚日志(Undo Log)。
重做日志记录了事务对数据库所做的修改操作,当系统发生故障时,MySQL可以通过重做日志来恢复数据库的一致性。
回滚日志记录了事务的撤销操作,当事务回滚时,MySQL可以通过回滚日志来撤销事务对数据库的修改。
通过使用重做日志和回滚日志,MySQL可以保证事务的原子性和持久性。而隔离性则通过锁机制和多版本并发控制(MVCC)来实现。一致性是通过其他三个特性来保证。
06:你是如何优化数据库操作的?
优化数据库操作可以提高系统的性能和响应速度。以下是一些常见的数据库操作优化方法:
使用索引:在数据库表中创建适当的索引可以加快查询速度。索引可以根据特定的列或列组合进行创建,以便快速定位和检索数据。
优化查询语句:编写高效的查询语句可以减少数据库的负载。避免使用不必要的连接、子查询和复杂的逻辑操作,尽量使用简单的查询语句。
适当分割表:当一个表的数据量过大时,可以考虑将其分割成多个表,以减少查询的数据量。可以根据业务需求将数据按照某个字段进行分割,例如按照时间范围或者地理位置进行分割。
合理设计数据库结构:良好的数据库设计可以提高查询和更新的效率。合理选择字段类型、设置主键和外键,避免冗余数据和不必要的表关联。
缓存数据:使用缓存可以减少对数据库的访问次数,提高系统的响应速度。可以使用内存缓存、分布式缓存或者数据库缓存等方式来缓存常用的数据。
定期优化数据库:定期进行数据库的维护和优化操作,例如清理无用数据、重新组织索引、优化表结构等,可以提高数据库的性能。
使用批量操作:对于需要批量处理的数据操作,可以使用批量插入、批量更新等方式,减少与数据库的交互次数,提高效率。
调整数据库参数:根据实际情况,适当调整数据库的参数配置,例如内存大小、并发连接数、缓冲区大小等,以提高数据库的性能。
以上是一些常见的数据库操作优化方法,根据具体的业务需求和数据库类型,可以选择适合的优化策略来提升系统性能。
07:为什么选择了使用RocketMQ作为消息中间件?
选择使用RocketMQ作为消息中间件有以下几个原因:
高吞吐量和低延迟:RocketMQ是一个高性能的消息中间件,能够处理大规模的消息并保持低延迟。它采用了多线程和零拷贝等技术,能够在保证高吞吐量的同时,降低消息传输的延迟。
可靠性和可扩展性:RocketMQ具有良好的可靠性和可扩展性。它采用了主从复制和消息落盘等机制,确保消息的可靠性。同时,RocketMQ支持水平扩展,可以根据业务需求灵活地扩展消息队列的数量和容量。
丰富的特性:RocketMQ提供了丰富的特性,包括消息顺序性、事务消息、消息过滤、延迟消息等。这些特性可以满足不同场景下的需求,使得RocketMQ适用于各种复杂的业务场景。
开源社区活跃:RocketMQ是一个开源项目,拥有活跃的开源社区。这意味着我们可以从社区中获取到最新的技术支持和解决方案,并且可以参与到项目的开发和改进中。
综上所述,RocketMQ作为一个高性能、可靠性强、功能丰富的消息中间件,能够满足我们的业务需求,因此我们选择使用RocketMQ作为消息中间件。
08:如何保证秒杀模块的高并发场景下不发生超卖情况?
在秒杀模块的高并发场景下,为了保证不发生超卖情况,可以采取以下几种策略:
限制库存数量:在秒杀开始前,设置一个固定的库存数量,每次有用户购买成功后,库存数量减少。当库存数量为0时,秒杀活动结束。这种方式可以有效避免超卖情况,但可能会导致部分用户无法购买到商品。
使用分布式锁:在秒杀操作中,使用分布式锁来保证同一时间只有一个用户可以进行购买操作。通过锁的机制,可以避免多个用户同时购买同一件商品的情况,从而避免超卖。
预减库存:在秒杀开始前,预先将商品的库存数量存储在缓存中,并在用户购买时从缓存中减少库存数量。这种方式可以减少对数据库的频繁访问,提高系统的并发能力。
限制用户购买数量:对于每个用户,限制其购买数量,防止一个用户购买过多的商品导致超卖情况的发生。
以上是一些常见的保证秒杀模块高并发场景下不发生超卖情况的策略,可以根据具体的业务需求选择适合的方式来实现。
09:在项目开发中,你是如何使用Git来进行版本控制的?
在项目开发中,我使用Git来进行版本控制。Git是一个分布式版本控制系统,它可以帮助我们跟踪和管理项目的代码变更。
首先,我会在项目的根目录下初始化一个Git仓库。使用命令git init
来初始化一个新的仓库。
然后,我会将项目的文件添加到Git的暂存区中,使用命令git add <file>
来添加指定文件,或者使用git add .
来添加所有文件。
接下来,我会提交文件的变更到Git仓库,使用命令git commit -m "<message>"
来提交变更,并附上一条简短的提交信息。
在开发过程中,我会频繁地使用git add
和git commit
命令来跟踪和提交代码的变更。
如果需要查看项目的提交历史,我可以使用git log
命令来查看所有的提交记录。
如果我需要回退到之前的某个版本,我可以使用git checkout <commit>
命令来切换到指定的提交。
当我需要与其他开发者合作时,我会使用Git的分支功能来进行并行开发。使用git branch <branch>
命令来创建一个新的分支,使用git checkout <branch>
命令来切换到指定的分支。
在合作开发过程中,我会使用git pull
命令来拉取远程仓库的最新代码,使用git push
命令来推送本地的代码变更到远程仓库。
总结来说,我使用Git来进行版本控制的流程如下:
初始化一个Git仓库:
git init
添加文件到暂存区:
git add <file>
或git add .
提交文件的变更:
git commit -m "<message>"
查看提交历史:
git log
切换到指定的提交:
git checkout <commit>
创建和切换分支:
git branch <branch>
和git checkout <branch>
拉取远程仓库的最新代码:
git pull
推送本地的代码变更到远程仓库:
git push
合并代码使用:
Git merge
使用Git进行版本控制可以帮助我们更好地管理项目的代码变更,方便团队协作和追踪项目的发展历程。
10:你在实现商品详情需要注意些什么,遇到过什么挑战吗?
实现商品详情页需要考虑以下几个方面:
页面布局:商品详情页的布局通常包括商品图片、商品标题、商品价格、商品描述、商品属性、购买按钮等内容。可以使用HTML和CSS来实现页面的布局和样式。
数据展示:需要从后端获取商品的相关信息,并将其展示在页面上。可以通过AJAX请求或者后端渲染的方式来获取数据,并使用JavaScript将数据填充到相应的位置。
图片展示:商品详情页通常需要展示商品的图片,可以使用图片轮播或者缩略图的方式来展示多张图片。
交互功能:商品详情页可能需要实现一些交互功能,比如加入购物车、收藏商品、选择商品属性等。可以使用JavaScript来实现这些交互功能,并与后端进行数据交互。
在实现商品详情页的过程中,可能会遇到以下挑战:
数据获取:需要与后端进行数据交互,获取商品的相关信息。可能需要处理异步请求、处理数据的格式转换等问题。
页面性能:商品详情页通常包含大量的图片和数据,需要考虑页面加载速度和性能优化的问题,以提升用户体验。
响应式设计:商品详情页需要适配不同的设备和屏幕尺寸,以提供良好的用户体验。需要考虑不同设备上的布局和样式调整。
安全性:商品详情页可能涉及用户的个人信息和支付信息,需要保证数据的安全性,防止信息泄露和恶意攻击。
以上是实现商品详情页的一般步骤和可能遇到的挑战,具体的实现方式和挑战因项目而异。
注意:充电桩项目代码已开源了,后台回复项目实战即可获取。
面试辅导:全程面试辅导,保驾护航!
个人技术博客可刷题:https://woaijava.cc/
回复77 ,获取《面试小抄2.0版》
回复电子书,获取《后端必读的200本电子书籍》
需要简历模板的请加我V (tj20120622),私发你。
相关文章:

16k面试中的10个问题
你好,我是田哥 节前,有位朋友跟我反馈面试中一些问题,这位朋友的基本情况: 坐标:上海,年限:3年不到,期望薪资;16k 下面我们来看看具体问题: 01:请…...

STM32单片机入门学习(六)-光敏传感器控制LED
光敏传感器模块和LED接线 LED负极接B12,正极接VCC 光敏传感模块一DO端接B13,GND接GND,VCC接VCC,AO不接。 如图: 主程序代码:main.c #include "stm32f10x.h" #include "Delay.h" //delay函数所在头文件 #include …...

MFC 鼠标悬停提示框
MFC 鼠标悬停提示框 运行效果 在MFC窗口中添加一个控件 工具栏中拖拽List Box到MFC窗口给List Box添加变量 CListBox m_listbox 增加成员变量 CWnd* m_tip_parent_wnd; CToolTipCtrl m_tip;给m_listbox创建提示框 void create_tip_window(CWnd* tip_wnd, CToolTipCtrl* ti…...

大数据学习,涉及哪些技术?
学习大数据需要涉及多种技术和概念,因为大数据领域非常广泛,涵盖了数据的采集、存储、处理、分析和可视化等多个方面。以下是学习大数据时需要考虑的一些关键技术和概念: 1、数据采集和存储: 数据库管理系统(DBMS&am…...

Clion中使用C/C++开发stm32程序
前言 从刚开始学习阶段,一直是用的keil5开发stm32程序,自从看到稚晖君推荐的CLion开发嵌入式程序后,这次尝试在CLion上开发stm32程序。 1、配置CLion用于STM32开发的环境 这里我就不详细写了,没必要重新写,网上教程很多…...

JavaScript Web APIs第五天笔记
Web APIs - 第5天笔记 目标: 能够利用JS操作浏览器,具备利用本地存储实现学生就业表的能力 BOM操作综合案例 js组成 JavaScript的组成 ECMAScript: 规定了js基础语法核心知识。比如:变量、分支语句、循环语句、对象等等 Web APIs : DOM 文档对象模型&…...

[ICCV-23] Paper List - 3D Generation-related
ICCV-23 paper list 目录 Oral Papers 3D from multi-view and sensors Generative AI Poster Papers 3D Generation (Neural generative models) 3D from a single image and shape-from-x 3D Editing Face and gestures Stylization Dataset Oral Papers 3D from …...

Transformer为什么如此有效 | 通用建模能力,并行
目录 1 更强更通用的建模能力 2 并行计算 3 大规模训练数据 4 多训练技巧的集成 Transformer是一种基于自注意力机制的网络,在最近一两年年可谓是大放异彩,我23年入坑CV的时候,我看到的CV工作似乎还没有一个不用到Transformer里的一些组…...

【初识Jmeter】【接口自动化】
jmeter的使用笔记1 Jmeter介绍与下载安装介绍安装配置配置与扩展组件 jmeter的使用基本功能元素登陆请求与提取cookie其他请求接口关联Cookie-响应成功聚合报告查看 Jmeter介绍与下载安装 介绍 jmeter是apache公司基于java开发的一款开源压力测试工具,体积小&…...

C:数组传值调用和传地址调用
传地址调用 对数组进行修改:排序… #include <stdio.h>// 函数用于交换两个整数的值 void swap(int *a, int *b) {int temp *a;*a *b;*b temp; }// 函数用于对整数数组进行升序排序 void sortArray(int *arr, int size) {for (int i 0; i < size - 1…...

Python数据容器——字典的常用操作(增、删、改、查)
作者:Insist-- 个人主页:insist--个人主页 本文专栏:Python专栏 专栏介绍:本专栏为免费专栏,并且会持续更新python基础知识,欢迎各位订阅关注. 目录 一、理解字典 1. Python字典是什么? 2. 字…...

JavaScript入门——(5)函数
1、为什么需要函数 函数:function,是被设计为执行特定任务的代码块 说明:函数可以把具有相同或相似逻辑的代码“包裹”起来,通过函数调用执行这些被“包裹”的代码逻辑,有利于精简代码方便复用。 比如之前使用的ale…...

数据库sql查询成绩第二高
select * from propro; #查询成绩第二高 select max(id) from propro where id <(select max(id) from propro); #查询成绩第二高的第二种方式 select * from (select * from propro order by id desc limit 2) as b order by id asc limit 1;...

十五、异常(5)
本章概要 异常限制构造器 异常限制 当覆盖方法的时候,只能抛出在基类方法的异常说明里列出的那些异常。这个限制很有用,因为这意味着与基类一起工作的代码,也能和导出类一起正常工作(这是面向对象的基本概念)&#…...

途虎养车上市、京东养车“震虎”,如何突围汽车后市场?
“汽车后市场第一股”终于来了! 赶在十一黄金周之前,途虎养车股份有限公司(09690.HK,下称“途虎养车”)于9月26日挂牌港交所,开盘价为28港元/股,与发行价持平;IPO首日报收29.50港元/股,涨幅5.3…...

【算法与数据结构】--算法基础--算法入门
一、什么是算法? 算法是一组有序的操作步骤,用于解决特定问题或执行特定任务。它是一种精确而有限的计算过程,以输入数据作为起点,经过一系列明确定义的步骤,最终产生输出结果。算法可以看作是一种计算机程序的抽象&a…...

AnyDesk密钥
最近最新的密钥:7K2CV32ER6T8F8I 这款软件应该是目前用的最好的可以免费的软件了,记录一下密钥...

C#(Csharp)我的基础教程(二)(我的菜鸟教程笔记)-属性和字段的探究与学习
目录 1、字段字段特点:2、属性属性的特点 1、字段 字段是定义在方法外面的变量,是成员变量,主要是为了类的内部数据交换使用,字段一般是用private修饰,也可以用readonly修饰,表示只读字段,其它…...

Programming abstractions in C阅读笔记:p176-p178
《Programming Abstractions In C》学习第59天,p176-p178总结。 一、技术总结 1.addtive sequences tn tn-1 tn-2 序列:3, 7, 10, 17, 27, 44, 71, 115, 186, 301, 487, 788, 1275, … p177, As a general class, the sequences that follow this…...

LeetCode-496-下一个更大元素
题目描述: 题目链接:LeetCode-496-下一个更大元素 解题思路: 方法一:暴力 方法二:单调栈 方法一代码实现: class Solution {public int[] nextGreaterElement(int[] nums1, int[] nums2) {// 最笨的方法&am…...

C++中的Lambda表达式
一、为什么要有lambda表达式 struct Goods {string _name; // 名字double _price; // 价格int _evaluate; // 评价Goods(const char* str, double price, int evaluate):_name(str), _price(price), _evaluate(evaluate){} }; 对于一个Goods类,需要对其中3个成员分…...

dockerfile搭建lnmp
systemctl stop firewalld systemctl disable firewalld setenforce 0 docker network create --subnet172.18.0.0/16 --opt "com.docker.network.bridge.name""docker1" mynetwork #部署nginx(容器IP 为 172.18.0.10) mkdir /…...

python之数据库操作详解
一般来说,我们对数据库里的操作需要先连接,创建游标对象,然后通过游标对象执行SQL语句去对SQL的数据进行操作,本篇文章旨在记录与科普。 1.cursor相关 元组是不可变的数据类型,只能查询,不能修改…...

完成flex布局与float布局
一、flex布局 <style>.nav {display: flex;background-color: #f8f8f8; /* 导航栏背景颜色 */}.nav a {flex: 1;display: flex;align-items: center;justify-content: center;padding: 14px 16px;text-decoration: none;color: #555555; /* 导航栏文字颜色 */}.nav a:ho…...

ThinkPHP团购拼购商城源码/带分销团购商城网站源码/完美版
ThinkPHP团购拼购商城源码,带分销团购商城网站源码,很完美的一套基于ThinkPHP开发的团购分销商城源码,界面也很大气,站长亲测。有需要的可以借鉴一下。 下载地址:https://bbs.csdn.net/topics/613231434...

awvs 中低危漏洞
低危 X-Frame-Options Header未配置 查看请求头中是否存在X-Frame-Options Header字段 会话Cookie中缺少secure属性(未设置安全标志的Cookie) 当cookie设置为Secure标志时,它指示浏览器只能通过安全SSL/TLS通道访问cookie。 未设置HttpOnly标志的Cookie 当cookie设置…...

openGauss学习笔记-95 openGauss 数据库管理-访问外部数据库-postgres_fdw
文章目录 openGauss学习笔记-95 openGauss 数据库管理-访问外部数据库-postgres_fdw95.1 使用postgres_fdw95.2 postgres_fdw下推主要成分95.3 常见问题95.4 注意事项 openGauss学习笔记-95 openGauss 数据库管理-访问外部数据库-postgres_fdw openGauss的fdw实现的功能是各个…...

并不止于表面理论和简单示例——《Python数据科学项目实战》
Python 现在可以说是运用最广泛的编程语言之一,使用 Python 的人不只局限在计算机相关专业的从业者,很多来自金融领域、医疗领域以及其他我们无法想象的领域的人,每天都在使用 Python处理各种数据、使用机器学习进行预测以及完成各种有趣的工作。 长久以来ÿ…...

skywalking功能介绍
目标 前置:性能监控-微服务链路追踪skywalking搭建-CSDN博客 使用skywalking进行链路监控,找到应用的时间消耗再哪。 服务 服务信息 请求接口后查看skywalking,可以看到有一个请求,响应时间为1852ms,性能指数Apdex…...

c++桥接模式,中介者模式应用实现状态跳转
上图为例,按上述两种方式实现的模式跳转,如果在原先的三种模式之间再增加多一种模式,就会引起每个模式都会要求改变,并且逻辑混乱,因此更改模式为桥接中介者访问,将抽象和实现分离,实现之间采用…...