后端开发面试题3(附答案)

前言

        在下首语言是golang,所以会用他作为示例。

原文参见 @arialdomartini的: Back-End Developer Interview Questions

设计模式相关问题

 1. 请用一个例子表明,全局对象是邪恶的存在。

        在Go语言中,虽然没有传统意义上的全局变量(全局对象),但可以通过包级别的变量来模拟全局对象的效果。全局变量在多个函数或包之间共享,有可能导致数据竞争和同步问题,进而引发程序的复杂性和潜在的bug。下面是一个简化的例子,展示全局对象在并发环境下的潜在问题:

package mainimport ("fmt""sync"
)// 全局对象模拟
var globalData = make(map[int]int)
var mutex = &sync.Mutex{}func increment(key int) {mutex.Lock()defer mutex.Unlock()globalData[key]++fmt.Printf("Incremented key %d to value %d\n", key, globalData[key])
}func decrement(key int) {mutex.Lock()defer mutex.Unlock()globalData[key]--if globalData[key] < 0 {globalData[key] = 0}fmt.Printf("Decremented key %d to value %d\n", key, globalData[key])
}func main() {go increment(1)go increment(1)go decrement(1)// 这里我们并没有等待goroutine完成,因此输出结果可能并不一致// 事实上,即使使用了互斥锁,由于全局对象的并发访问,仍然可能出现竞态条件
}

        在上述代码中,全局对象 globalData 是一个 map,我们在两个并发的goroutine中对其进行增减操作。尽管我们试图通过 mutex 来保护全局对象的并发访问,但在实际运行时,由于goroutine的调度不确定性,依然可能出现竞态条件,使得map中的值并不能保证总是预期的结果。这就是全局对象在并发编程中可能带来的问题。

        在实践中,应尽量避免过度使用全局对象,可以通过依赖注入、局部变量、闭包等方式传递数据,确保数据访问的明确性和可控性。如果确实需要全局状态,也应尽量采用线程安全的数据结构,并确保对其访问的同步控制恰当有效。

2. 假设你工作的系统不支持事务性,你会如何从头开始实现它?

        在不支持事务性的系统中实现事务性支持,通常需要从以下几个方面着手:

事务管理设计

        设计一套事务管理器,用于跟踪事务的状态(开始、进行中、提交、回滚)。

        为每个事务定义原子操作,确保每个操作要么全部执行成功,要么全部失败。

事务边界

        确定事务的开始和结束点,例如在开始事务时记录当前系统状态,在结束时根据事务的结果决定提交或回滚。

数据存储

        为支持事务,数据存储层需要有某种形式的版本控制或者影子副本机制,以便在事务失败时能够还原到事务开始前的状态。

补偿操作

        对于每个事务操作,定义相应的补偿操作(Rollback action),当事务需要回滚时,执行这些补偿操作以撤销已完成的更改。

一致性检查

        在提交事务前,进行一致性检查(如检查数据完整性约束),确保事务执行后的状态满足业务逻辑。

锁定和并发控制

        为了在并发环境下实现事务,需要实现锁定机制,如乐观锁、悲观锁等,以避免脏读、幻读、不可重复读等问题。

日志记录

        事务执行过程中,记录详细的日志信息,以便在出现问题时能够追踪事务的执行历史,以及用于在失败后进行事务恢复。

分布式事务支持

        如果系统是分布式环境,可能需要实现两阶段提交(2PC)、三阶段提交(3PC)或其他分布式事务协议来保证跨节点的一致性。

具体实现时,可以根据系统的具体技术和架构选择合适的方法,例如在数据库层面、应用服务层面或消息中间件层面实现事务控制。对于没有内置事务支持的数据库或数据存储系统,可能需要开发者手动实现以上的事务管理逻辑。

3. 什么是好莱坞原则(Hollywood Principles)?

        好莱坞原则(Hollywood Principle)来源于好莱坞的电影行业,但在软件工程中,这一原则被用来指导组件之间解耦和通信的设计哲学。在计算机编程和面向对象设计(OOD)中,好莱坞原则的主要表述是“Don't call us, we'll call you”(别找我们,我们会去找你)。

        在具体实践中,这意味着高层次的组件或框架(如好莱坞制片人)决定何时以及如何使用低层次的组件或服务(如演员)。低层次组件不需要知道或关心高层次组件的内部运作,只需提供必要的接口或回调函数,等待被调用。这样可以极大地减少组件间的耦合,提高系统的灵活性和可扩展性。

        在依赖注入(Dependency Injection,DI)和 inversion of control(IoC)容器的概念中,好莱坞原则得到了广泛应用。例如,一个对象不直接创建它的依赖对象,而是通过外部容器或框架传递进来,对象只需要声明它需要什么样的服务,而不必关心这些服务的具体实现和生命周期管理。当服务准备好时,容器会按照对象的要求提供服务,实现了“你不用来找我,我会去找你”的设计模式。

4. 关于迪米特法则(最少知识原则): 写一段代码违反它, 然后修复它。

        迪米特法则:the Law of Demeter, 最少知识原则: the Principle of Least Knowledge

        迪米特法则(Law of Demeter, LoD),又称最少知识原则,其基本思想是:一个对象应当对其他对象有最少的了解,也就是说,一个对象应当尽量少地与其他对象发生相互作用。当直接与一个对象互动时,尽量通过其提供的公共接口操作,而不是通过其内部的细节或间接访问其他对象。

        下面是一段违反迪米特法则的Go语言代码示例,以及如何修复它:

违反迪米特法则的代码示例:

package maintype Employee struct {Department *Department
}type Department struct {Manager *Manager
}type Manager struct {Name string
}func (e *Employee) GetManagerName() string {return e.Department.Manager.Name // 违反了迪米特法则,Employee直接访问了Department的Manager属性,然后又访问了Manager的Name属性
}func main() {dep := &Department{Manager: &Manager{Name: "John Doe"}}emp := &a

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

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

相关文章

【Rust日报】嵌入式 Rust:一份简化指南

EvilHelix 编辑器 EvilHelix 是一个采用 Vim 风格的模态编辑器&#xff0c;旨在提供快速且高效的编辑体验。它是 Helix 编辑器的一个分支&#xff0c;增加了 Vim binding&#xff0c;同时积极同步上游的特性&#xff0c;兼备了 Vim 和 Hexli 的优点&#xff1a; Vim 风格的模态…

blkio限制容器iops

/sys/fs/cgroup/blkio/blkio.throttle.read_iops_device /sys/fs/cgroup/blkio/blkio.throttle.write_iops_device lsblk 查看设备 kubectl get pod xxx -oyaml | grep -i id find / -name blkio.throttle.write_iops_device | grep id

栈和队列OJ题详解

一.有效的括号&#xff1a; 20. 有效的括号 - 力扣&#xff08;LeetCode&#xff09; 首先拿到这个题目&#xff0c;我的第一个思路是利用双指针来走&#xff0c;看看是不是匹配的 但是这种情况就把双指针的这个思路直接pass了&#xff0c;明明是匹配的括号&#xff0c;用双指…

1.3 Windows 的 CLion 开发环境安装

目录 1 C 语言的那些事 2 开发环境安装及新建项目 2.1 安装 MinGW 编译器 2.2 安装 CLion 开发环境

Android Audio基础——AudioFlinger回放录制线程(七)

AndioFlinger 作为 Android 的音频系统引擎,重任之一是负责输入输出流设备的管理及音频流数据的处理传输,这是由回放线程 PlaybackThread 及其派生的子类和录制线程 RecordThread 进行的。 一、基础介绍 1、关系图 ThreadBase:PlaybackThread 和 RecordThread 的基类。 Re…

人工智能最新的新闻动态

一、AI交互内容创新国际竞赛启动 主办单位&#xff1a;南京市科协启动时间&#xff1a;2024年5月26日目的与意义&#xff1a;鼓励全球科技人才参与AI创新&#xff0c;拓宽南京与海外科技人才的交流渠道&#xff0c;注入国际化活力&#xff0c;推动AI技术创新应用&#xff0c;挖…

react diff 原理

React的Diff算法&#xff08;也称为React Diff原理或React Diffing策略&#xff09;是React框架中用于优化DOM更新的核心机制。其核心思想是通过比较新旧Virtual DOM的差异&#xff0c;仅更新有变化的部分&#xff0c;以提高渲染效率。以下是React Diff算法的主要原理和策略&am…

【linux】多线程(2)

文章目录 线程的应用生产消费者模型自制锁生产消费队列成员参数生产函数消费函数 任务处理方式主函数 POSIX信号量sem_wait()sem_post() 线程池应用场景示例 单例模式饿汉实现单例 吃完饭, 立刻洗碗, 这种就是饿汉方式. 因为下一顿吃的时候可以立刻拿着碗就能吃饭.懒汉实现单例…

visual studio code生成代码模板

编写需要生成代码片段的代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"wid…

【C++】二分查找算法:x的平方根

1.题目 2.算法思路 看到题目可能不容易想到二分查找。 这题考察我们对算法的熟练程度。 二分查找的特点&#xff1a;数组具有二段性(不一定有序)。 题目中没有数组&#xff0c;我们可以造一个从0到x的数组&#xff0c;然后利用二分查找找到对应的值即可。 3.代码 class S…

ionic关于@angular版本报错解决方案(有效)

最近学校要求使用ionicangular学习&#xff0c;但是出现下面问题&#xff0c;这里我就分享一个我亲测有效的解决方案&#xff0c;提供学习&#xff08;在VScode中&#xff09; npm error code ERESOLVE npm error ERESOLVE could not resolve npm error npm error While resol…

C语言生成正弦波测试数据易懂版本

以往生成正弦波数据, 各个参数之间的关系总是不明确, 现在这个函数的代码非常明确的区分了各个参数之间的相互关系. #include <stdio.h> #include <math.h>/*** brief 生成正弦波测试数据* * param data 存放生成的数据的数组* param n 数据的长度 一共采样了多少…

源码编译安装LAMP(安装apeche mysql php 论坛 网站 巨详细版)

目录 一.LAMP架构相关概述 1.各组件作用 Linux&#xff08;平台&#xff09; Apache&#xff08;前台&#xff09; MySQL&#xff08;后台&#xff09; PHP/Perl/Python&#xff08;中间连接&#xff09; 总结 二.编译安装Apache httpd服务 1.关闭防火墙&#xff0c;将…

解决SpringBoot中插入汉字变成?(一秒解决)

在这里url后面加一行配置即可&useUnicodetrue&characterEncodingUTF-8即可 解释 spring.datasource.url: 这里包含了数据库的URL&#xff0c;以及额外的参数如useUnicodetrue用于启用Unicode字符集支持&#xff0c;characterEncodingUTF-8用于指定字符编码为UTF-8&…

Java面向对象-常用类(Math类)

常用类-Math类 Math 类提供了一序列基本数学运算和几何函数的方法。 Math类是类&#xff0c;并且它的所有成员变量和成员方法都是静态的。 1 Math类的常量和常用方法 常量 static doubleE 比任何其他值都更接近 e&#xff08;即自然对数的底数&#xff09;的 double 值。stati…

什么是SPI,和API有啥区别

Java 中区分 API 和 SPI&#xff0c;通俗的讲&#xff1a;API 和 SPI 都是相对的概念&#xff0c;他们的差别只在语义上&#xff0c;API 直接被应用开发人员使用&#xff0c;SPI 被框架扩展人员使用。 API (Application Programming Interface) 定义: API是一组定义了软件组件…

图像处理ASIC设计方法 笔记24 等价表和标记代换

&#xff08;一&#xff09;等价表的整理与压缩 1.1 等价关系的识别与追踪 在初步标记过程完成后&#xff0c;等价表的整理和压缩变得至关重要。这一阶段的首要任务是从等价表的地址1开始&#xff0c;对等价表进行逐个扫描。在扫描过程中&#xff0c;系统将检查每个临时标记是否…

链表类型的无界阻塞线程安全队列-ConcurrentLinkedQueue(FIFO)

ConcurrentLinkedQueue是非阻塞线程安全(volatile不能完全保证线程安全)的队列,适用于“高并发”的场景。是一个基于链表节点的无界线程安全队列,按照 FIFO(先进先出,尾先进头先出)原则对元素进行排序。队列元素中不可以放置null元素(内部实现的特殊节点除外)。 volati…

【rust工具链】

1 查看正在使用的工具链 命令&#xff1a;rustup show 结果显示&#xff1a; 从图中可以看到正在使用的是rustc 1.76.0版本&#xff0c;也可以看到已安装的所有版本的工具链 2 使用默认工具链 命令&#xff1a;rustup default 版本号 例如&#xff1a;rustup default 1.58…

【重学C语言】十五、文件操作

【重学C语言】十五、文件操作 文件的概念什么是流文件类型文本文件和二进制文件的区别文件指针文件指针常量预定义的文件指针stdin (标准输入)stdout (标准输出)stderr (标准错误输出)示例文件指针的声明使用文件指针悬挂指针示例文件缓冲区为什么需要缓冲区?缓冲区的类型缓冲…