C#接口与抽象类


一、接口与抽象类概述

在C#面向对象编程中,接口(Interface)抽象类(Abstract Class)都是实现抽象的重要机制,它们为代码提供了高级别的抽象能力,但各有特点和适用场景。

1. 基本概念对比

特性接口抽象类
关键字interfaceabstract class
实现方式完全抽象,不包含实现可包含部分实现
成员类型方法、属性、事件、索引器完整类成员(字段、方法等)
继承支持多实现仅支持单继承
构造函数不能有可以有
访问修饰符默认为public,不能使用其他可以使用各种访问修饰符

二、接口(Interface)详解

1. 接口定义与实现

// 定义接口
public interface ILogger
{
    void Log(string message);  // 接口成员默认public

    string GetLogs();

    // C#8.0起支持默认实现
    void Error(string message)
    {
        Log($"ERROR: {message}");
    }
}

// 实现接口
public class FileLogger : ILogger
{
    private readonly string _filePath;

    public FileLogger(string filePath)
    {
        _filePath = filePath;
    }

    public void Log(string message)
    {
        File.AppendAllText(_filePath, $"{DateTime.Now}: {message}\n");
    }

    public string GetLogs()
    {
        return File.Exists(_filePath) ? File.ReadAllText(_filePath) : string.Empty;
    }
}

2. 接口特性

  • 多实现:一个类可以实现多个接口
  • 接口继承:接口可以继承其他接口
  • 显式实现:解决命名冲突
public interface IDrawable
{
    void Draw();
}

public interface IResizable
{
    void Resize();
}

// 多接口实现
public class Circle : IDrawable, IResizable
{
    // 显式接口实现
    void IDrawable.Draw()
    {
        Console.WriteLine("绘制圆形");
    }

    void IResizable.Resize()
    {
        Console.WriteLine("调整圆形大小");
    }
}

三、抽象类(Abstract Class)详解

1. 抽象类定义与继承

// 定义抽象类
public abstract class Shape
{
    // 抽象方法(无实现)
    public abstract double CalculateArea();

    // 虚方法(有默认实现,可重写)
    public virtual void Draw()
    {
        Console.WriteLine("绘制基本形状");
    }

    // 普通方法
    public void PrintInfo()
    {
        Console.WriteLine($"面积:{CalculateArea()}");
    }
}

// 继承抽象类
public class Circle : Shape
{
    public double Radius { get; set; }

    public override double CalculateArea()
    {
        return Math.PI * Radius * Radius;
    }

    public override void Draw()
    {
        Console.WriteLine($"绘制圆形,半径:{Radius}");
    }
}

2. 抽象类特性

  • 部分实现:可以包含具体方法和抽象方法
  • 构造方法:可以有构造函数
  • 字段和属性:可以包含字段和完整属性
  • 单继承限制:C#不支持多继承

四、接口与抽象类的选择

1. 使用接口的场景

  • 需要多重继承时
  • 定义行为契约而不关心实现
  • 为不相关的类提供通用功能
  • 需要轻量级的约定时

2. 使用抽象类的场景

  • 多个相关类共享通用代码
  • 需要控制子类的创建方式(通过构造函数)
  • 需要提供基础实现,同时允许部分定制
  • 预期未来会有更多共同功能添加

五、高级应用

1. 接口的默认实现(C#8.0+)

public interface IOrder
{
    decimal Amount { get; }

    // 默认实现
    decimal CalculateTax()
    {
        return Amount * 0.1m;  // 10%税
    }
}

public class OnlineOrder : IOrder
{
    public decimal Amount { get; set; }
    // 可以选择不实现CalculateTax,使用默认实现
}

public class InternationalOrder : IOrder
{
    public decimal Amount { get; set; }

    // 覆盖默认实现
    public decimal CalculateTax()
    {
        return Amount * 0.05m;  // 5%税
    }
}

2. 抽象类与接口的组合使用

public interface IPlayable
{
    void Play();
    void Pause();
}

public abstract class MediaItem : IPlayable
{
    public string Title { get; set; }
    public TimeSpan Duration { get; set; }

    public abstract void Play();

    public virtual void Pause()
    {
        Console.WriteLine("媒体已暂停");
    }

    // 抽象类自己的方法
    public void DisplayInfo()
    {
        Console.WriteLine($"{Title} (时长:{Duration})");
    }
}

public class Audio : MediaItem
{
    public string Artist { get; set; }

    public override void Play()
    {
        Console.WriteLine($"正在播放音频:{Title} - {Artist}");
    }
}

public class Video : MediaItem
{
    public string Director { get; set; }

    public override void Play()
    {
        Console.WriteLine($"正在播放视频:{Title} (导演:{Director})");
    }

    public override void Pause()
    {
        Console.WriteLine("视频暂停,显示暂停画面");
    }
}

六、综合示例:支付系统设计

using System;

class Program
{
    static void Main()
    {
        PaymentProcessor processor = new PaymentProcessor();

        // 使用不同支付方式
        processor.ProcessPayment(new CreditCardPayment("1234-5678-9012-3456"), 100m);
        processor.ProcessPayment(new PayPalPayment("user@example.com"), 150m);
        processor.ProcessPayment(new BankTransferPayment("IBAN123456789"), 200m);
    }
}

// 支付接口
public interface IPaymentMethod
{
    string AccountInfo { get; }
    bool Authorize(decimal amount);
    void Process(decimal amount);
    void Confirm();
}

// 抽象支付基类
public abstract class PaymentBase : IPaymentMethod
{
    public string AccountInfo { get; protected set; }

    public abstract bool Authorize(decimal amount);

    public virtual void Process(decimal amount)
    {
        Console.WriteLine($"处理支付:{amount}元");
    }

    public virtual void Confirm()
    {
        Console.WriteLine("支付已确认");
    }
}

// 信用卡支付
public class CreditCardPayment : PaymentBase
{
    public CreditCardPayment(string cardNumber)
    {
        AccountInfo = $"信用卡尾号:{cardNumber.Substring(cardNumber.Length - 4)}";
    }

    public override bool Authorize(decimal amount)
    {
        Console.WriteLine($"授权信用卡支付:{amount}元");
        return true;  // 模拟授权成功
    }

    public override void Process(decimal amount)
    {
        base.Process(amount);
        Console.WriteLine("通过信用卡网关处理支付");
    }
}

// PayPal支付
public class PayPalPayment : PaymentBase
{
    public PayPalPayment(string email)
    {
        AccountInfo = $"PayPal账户:{email}";
    }

    public override bool Authorize(decimal amount)
    {
        Console.WriteLine($"验证PayPal账户并授权:{amount}元");
        return true;
    }

    public override void Process(decimal amount)
    {
        Console.WriteLine($"通过PayPal API处理支付:{amount}元");
    }
}

// 银行转账
public class BankTransferPayment : PaymentBase
{
    public BankTransferPayment(string iban)
    {
        AccountInfo = $"银行账户:{iban}";
    }

    public override bool Authorize(decimal amount)
    {
        Console.WriteLine("银行转账无需预授权");
        return true;
    }

    public override void Confirm()
    {
        Console.WriteLine("银行转账已发起,等待银行处理");
    }
}

// 支付处理器
public class PaymentProcessor
{
    public void ProcessPayment(IPaymentMethod paymentMethod, decimal amount)
    {
        Console.WriteLine($"\n使用 {paymentMethod.AccountInfo} 进行支付");

        if (paymentMethod.Authorize(amount))
        {
            paymentMethod.Process(amount);
            paymentMethod.Confirm();
        }
        else
        {
            Console.WriteLine("支付授权失败");
        }
    }
}

七、最佳实践与设计建议

  1. 接口设计原则
  • 保持接口小巧专注(ISP接口隔离原则)
  • 以”能力”而非”类型”命名接口(如ISortable而非ISorter
  • 避免”胖接口”,应该拆分为多个专门接口
  1. 抽象类设计建议
  • 为相关类提供有用的基础实现
  • 将可能变化的成员设为virtual或abstract
  • 避免过深的继承层次
  1. 组合使用策略
  • 优先使用接口定义契约
  • 使用抽象类提供通用实现
  • 考虑使用”接口+抽象类”的组合模式
  1. 版本控制考虑
  • 接口一旦发布难以修改(C#8.0的默认实现缓解了此问题)
  • 抽象类可以添加非抽象方法而不破坏现有代码
  1. 性能考量
  • 接口调用有轻微性能开销(虚拟表查找)
  • 抽象类方法调用通常更直接
  • 在性能关键路径上应考虑此差异

接口与抽象类是C#中实现抽象的两种强大工具,理解它们的异同点和适用场景,能够帮助开发者设计出更加灵活、可维护的面向对象系统。在实际开发中,经常需要根据具体需求灵活组合使用这两种机制。


发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注