接口的优势
- 灵活性高:一个类可以实现多个接口,便于实现多态和功能组合,在依赖注入中能更灵活地替换不同实现。
- 松耦合:依赖接口编程可以降低模块间的耦合度,使得代码更易于维护和扩展。
- 面向契约编程:定义了明确的行为契约,实现类必须严格遵守,利于团队协作和代码规范。
接口的劣势
- 无实现代码复用:接口不能包含实现代码,所有实现类都需自己实现接口方法,可能导致代码重复。
- 功能扩展性差:一旦接口定义后,修改接口会影响所有实现类,扩展性相对较弱。
抽象类的优势
- 代码复用:抽象类可以包含部分实现代码,子类可以继承并复用这些代码,减少重复代码。
- 更丰富的成员:抽象类可以包含字段、属性、非抽象方法等,比接口更具丰富性。
- 更好的扩展性:在抽象类中添加新的抽象方法或非抽象方法,对已有子类影响较小。
抽象类的劣势
- 继承单一性:C# 中一个类只能继承一个抽象类,限制了功能组合的灵活性。
- 耦合度较高:继承抽象类会使子类与抽象类之间耦合度相对较高,不利于代码的独立维护。
使用接口设计可插拔的日志记录模块
- 定义日志记录接口
public interface ILogger
{
void Log(string message);
}
- 具体实现类
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");
}
}
- 在需要使用日志记录的类中通过依赖注入使用
public class MyService
{
private readonly ILogger _logger;
public MyService(ILogger logger)
{
_logger = logger;
}
public void DoWork()
{
_logger.Log("Doing some work...");
}
}
使用抽象类设计可插拔的日志记录模块
- 定义抽象日志记录类
public abstract class LoggerBase
{
public abstract void Log(string message);
// 也可以有一些通用实现方法或属性
protected string FormatMessage(string message)
{
return $"{DateTime.Now}: {message}";
}
}
- 具体实现类
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");
}
}
- 在需要使用日志记录的类中通过依赖注入使用
public class MyService
{
private readonly LoggerBase _logger;
public MyService(LoggerBase logger)
{
_logger = logger;
}
public void DoWork()
{
_logger.Log("Doing some work...");
}
}