面试题答案
一键面试1. 依赖注入方案设计
首先定义HttpClient
和Logger
接口以及其实现类。假设HttpClient
用于发送网络请求,Logger
用于记录日志。
// HttpClient接口
interface HttpClient {
sendRequest(url: string, method: string, data?: any): Promise<any>;
}
// Logger接口
interface Logger {
log(message: string): void;
}
// HttpClient实现类
class RealHttpClient implements HttpClient {
async sendRequest(url: string, method: string, data?: any): Promise<any> {
// 实际的网络请求逻辑
return Promise.resolve({});
}
}
// Logger实现类
class RealLogger implements Logger {
log(message: string): void {
console.log(message);
}
}
// UserService类,依赖HttpClient和Logger
class UserService {
private httpClient: HttpClient;
private logger: Logger;
constructor(httpClient: HttpClient, logger: Logger) {
this.httpClient = httpClient;
this.logger = logger;
}
async getUserData(userId: string) {
try {
const response = await this.httpClient.sendRequest(`/users/${userId}`, 'GET');
this.logger.log(`Fetched user data for ${userId}`);
return response;
} catch (error) {
this.logger.log(`Error fetching user data for ${userId}: ${error}`);
throw error;
}
}
}
2. 如何使用依赖注入
在应用的入口或模块初始化阶段,可以这样创建UserService
实例:
// 创建HttpClient和Logger实例
const httpClient = new RealHttpClient();
const logger = new RealLogger();
// 使用依赖注入创建UserService实例
const userService = new UserService(httpClient, logger);
3. 避免循环依赖问题
- 正向依赖原则:确保依赖关系是单向的,尽量让高层次模块依赖低层次模块,而不是相互依赖。例如在上述例子中,
UserService
依赖HttpClient
和Logger
,这两个类不应该反过来依赖UserService
。 - 提前实例化:在应用启动时,尽早实例化所有需要的依赖。通过在入口处创建所有单例实例,可以确保在任何类尝试访问依赖之前,依赖已经被创建,从而避免循环依赖。例如在上述代码中,先创建
httpClient
和logger
,再创建userService
。 - 使用接口隔离:通过接口来定义依赖关系,而不是具体的实现类。这样可以降低耦合度,减少循环依赖的可能性。例如
UserService
依赖HttpClient
和Logger
接口,而不是具体的RealHttpClient
和RealLogger
类,这使得代码结构更加清晰,并且在替换实现时更加容易。