云计算百科
云计算领域专业知识百科平台

第06章-接口与抽象

第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] 支付处理失败

赞(0)
未经允许不得转载:网硕互联帮助中心 » 第06章-接口与抽象
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!