第6章 接口与抽象
章节摘要
本章学习接口的定义与实现、接口的多实现和继承、显式接口实现的使用场景、接口与抽象类的区别和选择,通过实战项目掌握接口在实际开发中的应用,为构建松耦合、可扩展的应用程序奠定基础。
本章目录
- 6.1 接口的定义与实现
- 6.2 接口的多实现
- 6.3 显式接口实现
- 6.4 接口与抽象类的区别
- 6.5 实战练习
6.1 接口的定义与实现
什么是接口
**接口(Interface)**定义了一组成员的契约,但不提供实现。类实现接口后必须提供所有成员的具体实现。
// 定义接口
interface IAnimal
{
// 接口成员(默认public)
string Name { get; set; }
void MakeSound();
void Move();
}
// 实现接口
class Dog : IAnimal
{
public string Name { get; set; }
public void MakeSound()
{
Console.WriteLine($"{Name} 说:汪汪汪!");
}
public void Move()
{
Console.WriteLine($"{Name} 正在跑步");
}
}
// 使用
Dog dog = new Dog { Name = "旺财" };
dog.MakeSound(); // 旺财 说:汪汪汪!
dog.Move(); // 旺财 正在跑步
接口的特点
interface IExample
{
// ✅ 可以包含的成员
void Method(); // 方法
int Property { get; set; } // 属性
int this[int index] { get; set; } // 索引器
event EventHandler Event; // 事件
// C# 8.0+:默认实现
void DefaultMethod()
{
Console.WriteLine("默认实现");
}
// C# 8.0+:静态成员
static void StaticMethod()
{
Console.WriteLine("静态方法");
}
}
// ❌ 接口不能包含
// – 字段
// – 构造函数
// – 析构函数
// – 实例字段
接口命名规范
// ✅ 接口名以I开头(推荐)
interface IComparable { }
interface IDisposable { }
interface IEnumerable { }
// 描述能力的接口名
interface IReadable { }
interface IWritable { }
interface ISerializable { }
实现接口示例
// 定义接口
interface IShape
{
double GetArea();
double GetPerimeter();
void Draw();
}
// 实现接口
class Circle : IShape
{
public double Radius { get; set; }
public Circle(double radius)
{
Radius = radius;
}
public double GetArea()
{
return Math.PI * Radius * Radius;
}
public double GetPerimeter()
{
return 2 * Math.PI * Radius;
}
public void Draw()
{
Console.WriteLine($"绘制半径为 {Radius} 的圆形");
}
}
class Rectangle : IShape
{
public double Width { get; set; }
public double Height { get; set; }
public Rectangle(double width, double height)
{
Width = width;
Height = height;
}
public double GetArea()
{
return Width * Height;
}
public double GetPerimeter()
{
return 2 * (Width + Height);
}
public void Draw()
{
Console.WriteLine($"绘制 {Width}×{Height} 的矩形");
}
}
// 使用接口
IShape shape1 = new Circle(5);
IShape shape2 = new Rectangle(4, 6);
Console.WriteLine($"圆形面积:{shape1.GetArea():F2}");
Console.WriteLine($"矩形面积:{shape2.GetArea():F2}");
shape1.Draw();
shape2.Draw();
6.2 接口的多实现
实现多个接口
一个类可以实现多个接口:
interface IReadable
{
void Read();
}
interface IWritable
{
void Write(string content);
}
interface ICloseable
{
void Close();
}
// 实现多个接口
class File : IReadable, IWritable, ICloseable
{
private string content = "";
private bool isOpen = true;
public void Read()
{
if (!isOpen)
{
Console.WriteLine("文件已关闭");
return;
}
Console.WriteLine($"读取内容:{content}");
}
public void Write(string content)
{
if (!isOpen)
{
Console.WriteLine("文件已关闭");
return;
}
this.content = content;
Console.WriteLine($"写入内容:{content}");
}
public void Close()
{
isOpen = false;
Console.WriteLine("文件已关闭");
}
}
// 使用
File file = new File();
file.Write("Hello, World!");
file.Read();
file.Close();
file.Read(); // 文件已关闭
接口继承
接口可以继承其他接口:
interface IAnimal
{
void Eat();
}
interface IMammal : IAnimal
{
void GiveBirth();
}
interface IPet : IAnimal
{
string Owner { get; set; }
void Play();
}
// 实现继承的接口
class Dog : IMammal, IPet
{
public string Owner { get; set; }
// 实现IAnimal
public void Eat()
{
Console.WriteLine("狗在吃东西");
}
// 实现IMammal
public void GiveBirth()
{
Console.WriteLine("狗生小狗");
}
// 实现IPet
public void Play()
{
Console.WriteLine($"{Owner}在和狗玩耍");
}
}
接口作为参数
interface IPayment
{
bool Pay(decimal amount);
string GetPaymentMethod();
}
class CreditCard : IPayment
{
public bool Pay(decimal amount)
{
Console.WriteLine($"使用信用卡支付 {amount:C}");
return true;
}
public string GetPaymentMethod()
{
return "信用卡";
}
}
class Alipay : IPayment
{
public bool Pay(decimal amount)
{
Console.WriteLine($"使用支付宝支付 {amount:C}");
return true;
}
public string GetPaymentMethod()
{
return "支付宝";
}
}
// 接受接口作为参数
class PaymentProcessor
{
public void ProcessPayment(IPayment payment, decimal amount)
{
Console.WriteLine($"支付方式:{payment.GetPaymentMethod()}");
if (payment.Pay(amount))
{
Console.WriteLine("支付成功!");
}
else
{
Console.WriteLine("支付失败!");
}
}
}
// 使用
PaymentProcessor processor = new PaymentProcessor();
processor.ProcessPayment(new CreditCard(), 100);
processor.ProcessPayment(new Alipay(), 200);
6.3 显式接口实现
为什么需要显式实现
当类实现多个接口,且接口有同名成员时,使用显式实现避免冲突:
interface IEnglishSpeaker
{
void Greet();
}
interface IChineseSpeaker
{
void Greet();
}
// 显式接口实现
class Bilingual : IEnglishSpeaker, IChineseSpeaker
{
// 显式实现IEnglishSpeaker.Greet
void IEnglishSpeaker.Greet()
{
Console.WriteLine("Hello!");
}
// 显式实现IChineseSpeaker.Greet
void IChineseSpeaker.Greet()
{
Console.WriteLine("你好!");
}
}
// 使用显式实现
Bilingual person = new Bilingual();
// person.Greet(); // 编译错误:无法直接调用
// 必须通过接口引用调用
IEnglishSpeaker english = person;
english.Greet(); // Hello!
IChineseSpeaker chinese = person;
chinese.Greet(); // 你好!
显式实现的特点
interface IExample
{
void Method();
int Property { get; set; }
}
class MyClass : IExample
{
// 显式实现的成员
void IExample.Method()
{
Console.WriteLine("显式实现的方法");
}
int IExample.Property { get; set; }
// 显式实现的特点:
// 1. 不能有访问修饰符
// 2. 只能通过接口引用访问
// 3. 不能是virtual、abstract或override
}
MyClass obj = new MyClass();
// obj.Method(); // 错误:无法访问
IExample example = obj;
example.Method(); // 正确
混合实现
interface ILogger
{
void Log(string message);
void LogError(string error);
}
class ConsoleLogger : ILogger
{
// 隐式实现(公共方法)
public void Log(string message)
{
Console.WriteLine($"[INFO] {message}");
}
// 显式实现(只能通过接口访问)
void ILogger.LogError(string error)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"[ERROR] {error}");
Console.ResetColor();
}
}
ConsoleLogger logger = new ConsoleLogger();
logger.Log("普通消息"); // 可以直接调用
// logger.LogError("错误"); // 错误:无法访问
ILogger iLogger = logger;
iLogger.LogError("错误消息"); // 必须通过接口
6.4 接口与抽象类的区别
对比表
| 继承数量 | 可以实现多个 | 只能继承一个 |
| 成员实现 | 默认无实现(C# 8.0+可有默认实现) | 可以有实现 |
| 字段 | 不能有字段 | 可以有字段 |
| 构造函数 | 不能有 | 可以有 |
| 访问修饰符 | 成员默认public | 可以有各种修饰符 |
| 用途 | 定义能力/契约 | 定义"是什么" |
使用场景对比
// 接口:定义能力
interface IFlyable
{
void Fly();
}
interface ISwimmable
{
void Swim();
}
// 抽象类:定义"是什么"
abstract class Animal
{
public string Name { get; set; }
public abstract void MakeSound();
public void Sleep()
{
Console.WriteLine($"{Name} 正在睡觉");
}
}
// 鸟类:是动物,能飞
class Bird : Animal, IFlyable
{
public override void MakeSound()
{
Console.WriteLine("鸟在叫");
}
public void Fly()
{
Console.WriteLine($"{Name} 正在飞翔");
}
}
// 鸭子:是动物,能飞也能游泳
class Duck : Animal, IFlyable, ISwimmable
{
public override void MakeSound()
{
Console.WriteLine("嘎嘎嘎");
}
public void Fly()
{
Console.WriteLine($"{Name} 正在飞");
}
public void Swim()
{
Console.WriteLine($"{Name} 正在游泳");
}
}
选择建议
// ✅ 使用接口的场景
// 1. 定义不相关类的共同能力
interface IComparable
{
int CompareTo(object obj);
}
// 2. 支持多重继承
class MyClass : BaseClass, IInterface1, IInterface2 { }
// 3. 定义契约,不关心实现
interface IRepository<T>
{
void Add(T item);
T GetById(int id);
}
// ✅ 使用抽象类的场景
// 1. 有共同的实现代码
abstract class Shape
{
public string Color { get; set; }
public void SetColor(string color)
{
Color = color;
}
public abstract double GetArea();
}
// 2. 需要字段或构造函数
abstract class Vehicle
{
protected int speed;
public Vehicle(int initialSpeed)
{
speed = initialSpeed;
}
}
// 3. 定义类层次结构
abstract class Employee
{
public string Name { get; set; }
public abstract decimal CalculateSalary();
}
6.5 实战练习
练习1:图形计算器
要求: 创建一个图形计算器系统,实现以下功能:
- 定义 IShape 接口,包含计算面积和周长的方法
- 实现多个图形类(圆形、矩形、三角形)
- 创建图形数组并计算总面积
完整解决方案:
// 定义图形接口
interface IShape
{
double GetArea();
double GetPerimeter();
string GetName();
}
// 圆形
class Circle : IShape
{
public double Radius { get; set; }
public Circle(double radius)
{
Radius = radius;
}
public double GetArea()
{
return Math.PI * Radius * Radius;
}
public double GetPerimeter()
{
return 2 * Math.PI * Radius;
}
public string GetName()
{
return "圆形";
}
}
// 矩形
class Rectangle : IShape
{
public double Width { get; set; }
public double Height { get; set; }
public Rectangle(double width, double height)
{
Width = width;
Height = height;
}
public double GetArea()
{
return Width * Height;
}
public double GetPerimeter()
{
return 2 * (Width + Height);
}
public string GetName()
{
return "矩形";
}
}
// 三角形
class Triangle : IShape
{
public double SideA { get; set; }
public double SideB { get; set; }
public double SideC { get; set; }
public Triangle(double a, double b, double c)
{
SideA = a;
SideB = b;
SideC = c;
}
public double GetArea()
{
// 使用海伦公式
double s = (SideA + SideB + SideC) / 2;
return Math.Sqrt(s * (s – SideA) * (s – SideB) * (s – SideC));
}
public double GetPerimeter()
{
return SideA + SideB + SideC;
}
public string GetName()
{
return "三角形";
}
}
// 图形计算器
class ShapeCalculator
{
public void DisplayShapeInfo(IShape shape)
{
Console.WriteLine($"\\n{shape.GetName()}信息:");
Console.WriteLine($" 面积:{shape.GetArea():F2}");
Console.WriteLine($" 周长:{shape.GetPerimeter():F2}");
}
public double CalculateTotalArea(IShape[] shapes)
{
double total = 0;
for (int i = 0; i < shapes.Length; i++)
{
total += shapes[i].GetArea();
}
return total;
}
public IShape FindLargestShape(IShape[] shapes)
{
if (shapes.Length == 0)
{
return null;
}
IShape largest = shapes[0];
double maxArea = shapes[0].GetArea();
for (int i = 1; i < shapes.Length; i++)
{
double area = shapes[i].GetArea();
if (area > maxArea)
{
maxArea = area;
largest = shapes[i];
}
}
return largest;
}
}
// 测试代码
Console.WriteLine("=== 图形计算器测试 ===");
ShapeCalculator calculator = new ShapeCalculator();
// 创建图形数组
IShape[] shapes = new IShape[4];
shapes[0] = new Circle(5);
shapes[1] = new Rectangle(4, 6);
shapes[2] = new Triangle(3, 4, 5);
shapes[3] = new Circle(3);
// 显示每个图形的信息
for (int i = 0; i < shapes.Length; i++)
{
calculator.DisplayShapeInfo(shapes[i]);
}
// 计算总面积
double totalArea = calculator.CalculateTotalArea(shapes);
Console.WriteLine($"\\n所有图形的总面积:{totalArea:F2}");
// 找出最大的图形
IShape largest = calculator.FindLargestShape(shapes);
Console.WriteLine($"\\n面积最大的图形:{largest.GetName()},面积:{largest.GetArea():F2}");
运行示例:
=== 图形计算器测试 ===
圆形信息:
面积:78.54
周长:31.42
矩形信息:
面积:24.00
周长:20.00
三角形信息:
面积:6.00
周长:12.00
圆形信息:
面积:28.27
周长:18.85
所有图形的总面积:136.81
面积最大的图形:圆形,面积:78.54
练习2:数据验证系统
要求: 创建一个数据验证系统,实现以下功能:
- 定义 IValidator 接口
- 实现多种验证器(邮箱验证、年龄验证、用户名验证)
- 支持批量验证
完整解决方案:
// 验证结果类
class ValidationResult
{
public bool IsValid { get; set; }
public string ErrorMessage { get; set; }
public ValidationResult(bool isValid, string errorMessage = "")
{
IsValid = isValid;
ErrorMessage = errorMessage;
}
}
// 验证器接口
interface IValidator
{
ValidationResult Validate(string value);
string GetValidatorName();
}
// 邮箱验证器
class EmailValidator : IValidator
{
public ValidationResult Validate(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
return new ValidationResult(false, "邮箱不能为空");
}
if (!value.Contains("@"))
{
return new ValidationResult(false, "邮箱格式不正确,缺少@符号");
}
int atIndex = value.IndexOf("@");
if (atIndex == 0 || atIndex == value.Length – 1)
{
return new ValidationResult(false, "邮箱格式不正确");
}
return new ValidationResult(true);
}
public string GetValidatorName()
{
return "邮箱验证器";
}
}
// 年龄验证器
class AgeValidator : IValidator
{
private int minAge;
private int maxAge;
public AgeValidator(int minAge, int maxAge)
{
this.minAge = minAge;
this.maxAge = maxAge;
}
public ValidationResult Validate(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
return new ValidationResult(false, "年龄不能为空");
}
if (!int.TryParse(value, out int age))
{
return new ValidationResult(false, "年龄必须是数字");
}
if (age < minAge || age > maxAge)
{
return new ValidationResult(false, $"年龄必须在{minAge}–{maxAge}之间");
}
return new ValidationResult(true);
}
public string GetValidatorName()
{
return "年龄验证器";
}
}
// 用户名验证器
class UsernameValidator : IValidator
{
private int minLength;
public UsernameValidator(int minLength)
{
this.minLength = minLength;
}
public ValidationResult Validate(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
return new ValidationResult(false, "用户名不能为空");
}
if (value.Length < minLength)
{
return new ValidationResult(false, $"用户名长度至少{minLength}个字符");
}
// 检查是否只包含字母、数字和下划线
for (int i = 0; i < value.Length; i++)
{
char c = value[i];
if (!char.IsLetterOrDigit(c) && c != '_')
{
return new ValidationResult(false, "用户名只能包含字母、数字和下划线");
}
}
return new ValidationResult(true);
}
public string GetValidatorName()
{
return "用户名验证器";
}
}
// 验证管理器
class ValidationManager
{
public void ValidateAll(IValidator[] validators, string[] values)
{
Console.WriteLine("=== 开始批量验证 ===\\n");
for (int i = 0; i < validators.Length; i++)
{
Console.WriteLine($"使用 {validators[i].GetValidatorName()} 验证:{values[i]}");
ValidationResult result = validators[i].Validate(values[i]);
if (result.IsValid)
{
Console.WriteLine(" ✓ 验证通过");
}
else
{
Console.WriteLine($" ✗ 验证失败:{result.ErrorMessage}");
}
Console.WriteLine();
}
}
}
// 测试代码
Console.WriteLine("=== 数据验证系统测试 ===\\n");
ValidationManager manager = new ValidationManager();
// 创建验证器数组
IValidator[] validators = new IValidator[4];
validators[0] = new EmailValidator();
validators[1] = new EmailValidator();
validators[2] = new AgeValidator(18, 60);
validators[3] = new UsernameValidator(3);
// 待验证的数据
string[] testData = new string[4];
testData[0] = "user@example.com";
testData[1] = "invalid-email";
testData[2] = "25";
testData[3] = "ab";
// 执行验证
manager.ValidateAll(validators, testData);
运行示例:
=== 数据验证系统测试 ===
=== 开始批量验证 ===
使用 邮箱验证器 验证:user@example.com
✓ 验证通过
使用 邮箱验证器 验证:invalid-email
✗ 验证失败:邮箱格式不正确,缺少@符号
使用 年龄验证器 验证:25
✓ 验证通过
使用 用户名验证器 验证:ab
✗ 验证失败:用户名长度至少3个字符
练习3:日志记录系统
要求: 创建一个日志记录系统,实现以下功能:
- 定义 ILogger 接口
- 实现多种日志记录器(控制台、文件、组合日志)
- 支持不同日志级别
完整解决方案:
// 日志级别枚举
enum LogLevel
{
Info,
Warning,
Error
}
// 日志接口
interface ILogger
{
void Log(string message, LogLevel level);
string GetLoggerName();
}
// 控制台日志记录器
class ConsoleLogger : ILogger
{
public void Log(string message, LogLevel level)
{
string prefix = GetLevelPrefix(level);
Console.WriteLine($"{prefix} {message}");
}
public string GetLoggerName()
{
return "控制台日志";
}
private string GetLevelPrefix(LogLevel level)
{
if (level == LogLevel.Info)
return "[INFO]";
else if (level == LogLevel.Warning)
return "[WARNING]";
else
return "[ERROR]";
}
}
// 文件日志记录器
class FileLogger : ILogger
{
private string filePath;
public FileLogger(string filePath)
{
this.filePath = filePath;
}
public void Log(string message, LogLevel level)
{
string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
string prefix = GetLevelPrefix(level);
string logEntry = $"[{timestamp}] {prefix} {message}";
// 追加到文件
File.AppendAllText(filePath, logEntry + "\\n");
}
public string GetLoggerName()
{
return "文件日志";
}
private string GetLevelPrefix(LogLevel level)
{
if (level == LogLevel.Info)
return "[INFO]";
else if (level == LogLevel.Warning)
return "[WARNING]";
else
return "[ERROR]";
}
}
// 组合日志记录器(同时记录到多个目标)
class CompositeLogger : ILogger
{
private ILogger[] loggers;
public CompositeLogger(ILogger[] loggers)
{
this.loggers = loggers;
}
public void Log(string message, LogLevel level)
{
for (int i = 0; i < loggers.Length; i++)
{
loggers[i].Log(message, level);
}
}
public string GetLoggerName()
{
return "组合日志";
}
}
// 日志管理器
class LogManager
{
private ILogger logger;
public LogManager(ILogger logger)
{
this.logger = logger;
}
public void LogInfo(string message)
{
logger.Log(message, LogLevel.Info);
}
public void LogWarning(string message)
{
logger.Log(message, LogLevel.Warning);
}
public void LogError(string message)
{
logger.Log(message, LogLevel.Error);
}
public void DisplayLoggerInfo()
{
Console.WriteLine($"当前使用的日志记录器:{logger.GetLoggerName()}");
}
}
// 测试代码
Console.WriteLine("=== 日志记录系统测试 ===\\n");
// 测试1:使用控制台日志
Console.WriteLine("— 测试1:控制台日志 —");
ILogger consoleLogger = new ConsoleLogger();
LogManager manager1 = new LogManager(consoleLogger);
manager1.DisplayLoggerInfo();
manager1.LogInfo("应用程序启动");
manager1.LogWarning("配置文件未找到,使用默认配置");
manager1.LogError("数据库连接失败");
// 测试2:使用文件日志
Console.WriteLine("\\n— 测试2:文件日志 —");
string logFile = "app.log";
ILogger fileLogger = new FileLogger(logFile);
LogManager manager2 = new LogManager(fileLogger);
manager2.DisplayLoggerInfo();
manager2.LogInfo("用户登录成功");
manager2.LogWarning("磁盘空间不足");
Console.WriteLine($"日志已写入文件:{logFile}");
// 测试3:使用组合日志(同时输出到控制台和文件)
Console.WriteLine("\\n— 测试3:组合日志 —");
ILogger[] loggerArray = new ILogger[2];
loggerArray[0] = new ConsoleLogger();
loggerArray[1] = new FileLogger(logFile);
ILogger compositeLogger = new CompositeLogger(loggerArray);
LogManager manager3 = new LogManager(compositeLogger);
manager3.DisplayLoggerInfo();
manager3.LogInfo("订单创建成功");
manager3.LogError("支付处理失败");
运行示例:
=== 日志记录系统测试 ===
— 测试1:控制台日志 —
当前使用的日志记录器:控制台日志
[INFO] 应用程序启动
[WARNING] 配置文件未找到,使用默认配置
[ERROR] 数据库连接失败
— 测试2:文件日志 —
当前使用的日志记录器:文件日志
日志已写入文件:app.log
— 测试3:组合日志 —
当前使用的日志记录器:组合日志
[INFO] 订单创建成功
[ERROR] 支付处理失败
网硕互联帮助中心






评论前必须登录!
注册