MST

星途 面试题库

面试题:C#中接口与抽象类在依赖注入场景下的应用

在依赖注入场景中,C#的接口和抽象类分别有哪些优势和劣势?如果要设计一个可插拔的日志记录模块,使用接口和抽象类分别应该如何设计?
16.2万 热度难度
编程语言C#

知识考点

AI 面试

面试题答案

一键面试

接口的优势

  1. 灵活性高:一个类可以实现多个接口,便于实现多态和功能组合,在依赖注入中能更灵活地替换不同实现。
  2. 松耦合:依赖接口编程可以降低模块间的耦合度,使得代码更易于维护和扩展。
  3. 面向契约编程:定义了明确的行为契约,实现类必须严格遵守,利于团队协作和代码规范。

接口的劣势

  1. 无实现代码复用:接口不能包含实现代码,所有实现类都需自己实现接口方法,可能导致代码重复。
  2. 功能扩展性差:一旦接口定义后,修改接口会影响所有实现类,扩展性相对较弱。

抽象类的优势

  1. 代码复用:抽象类可以包含部分实现代码,子类可以继承并复用这些代码,减少重复代码。
  2. 更丰富的成员:抽象类可以包含字段、属性、非抽象方法等,比接口更具丰富性。
  3. 更好的扩展性:在抽象类中添加新的抽象方法或非抽象方法,对已有子类影响较小。

抽象类的劣势

  1. 继承单一性:C# 中一个类只能继承一个抽象类,限制了功能组合的灵活性。
  2. 耦合度较高:继承抽象类会使子类与抽象类之间耦合度相对较高,不利于代码的独立维护。

使用接口设计可插拔的日志记录模块

  1. 定义日志记录接口
public interface ILogger
{
    void Log(string message);
}
  1. 具体实现类
public class ConsoleLogger : ILogger
{
    public void Log(string message)
    {
        Console.WriteLine($"Console Log: {message}");
    }
}

public class FileLogger : ILogger
{
    public void Log(string message)
    {
        File.AppendAllText("log.txt", $"File Log: {message}\n");
    }
}
  1. 在需要使用日志记录的类中通过依赖注入使用
public class MyService
{
    private readonly ILogger _logger;
    public MyService(ILogger logger)
    {
        _logger = logger;
    }
    public void DoWork()
    {
        _logger.Log("Doing some work...");
    }
}

使用抽象类设计可插拔的日志记录模块

  1. 定义抽象日志记录类
public abstract class LoggerBase
{
    public abstract void Log(string message);
    // 也可以有一些通用实现方法或属性
    protected string FormatMessage(string message)
    {
        return $"{DateTime.Now}: {message}";
    }
}
  1. 具体实现类
public class ConsoleLogger : LoggerBase
{
    public override void Log(string message)
    {
        string formattedMessage = FormatMessage(message);
        Console.WriteLine($"Console Log: {formattedMessage}");
    }
}

public class FileLogger : LoggerBase
{
    public override void Log(string message)
    {
        string formattedMessage = FormatMessage(message);
        File.AppendAllText("log.txt", $"File Log: {formattedMessage}\n");
    }
}
  1. 在需要使用日志记录的类中通过依赖注入使用
public class MyService
{
    private readonly LoggerBase _logger;
    public MyService(LoggerBase logger)
    {
        _logger = logger;
    }
    public void DoWork()
    {
        _logger.Log("Doing some work...");
    }
}