C# 接口和类

1 接口

        当需要定义一组方法或属性,但不关心具体实现时,可以使用接口。当然,如果是开发小型工具类或者内部工具、小型项目时可以不使用接口,直接使用类,但如果是大型项目、框架设计或需要支持插件化的场景,则最好使用接口。

        从 C# 8.0 开始,接口可以包含默认实现,但实现类仍然可以选择重写默认实现。

1.1 接口的优势

        1、统一标准,支持多态

        通过接口,可以将不同的类视为同一类型,从而实现多态性。比如:一个接口可以被不同的类实现,然后通过接口去调用这些类的方法。

        2、解耦

        接口可以将定义与实现分离,降低代码的耦合度。

        3、支持多重继承

        一个类可以继承多个接口,从而在该类实现不同接口的方法。

interface IShape
{
    void Draw();
}

interface IColor
{
    void SetColor(string color);
}

class Circle : IShape, IColor
{
    public void Draw()
    {
        Console.WriteLine("Drawing a circle");
    }

    public void SetColor(string color)
    {
        Console.WriteLine("Setting color to " + color);
    }
}

        4、使用接口可以让依赖可替换,使单元测试更容易

        5、扩展性高

        接口将定义与实现分离,调用方代码依赖于接口(抽象),而不是具体的实现类。这样,当需要替换或扩展实现时,只需要提供新的实现类,而不需要修改调用方的代码。

        如:有一个支付系统,最初只支持信用卡支付,但未来可能需要支持更多的支付方式(如支付宝、微信支付等)。如果直接使用类,扩展性会很差;而使用接口,则可以轻松扩展。

        直接使用类:

class CreditCardPayment
{
    public void Pay(decimal amount)
    {
        Console.WriteLine($"Paid {amount} via Credit Card");
    }
}

class PaymentProcessor
{
    private CreditCardPayment _payment;

    public PaymentProcessor()
    {
        _payment = new CreditCardPayment(); // 直接依赖具体类
    }

    public void ProcessPayment(decimal amount)
    {
        _payment.Pay(amount);
    }
}

class Program
{
    static void Main(string[] args)
    {
        PaymentProcessor processor = new PaymentProcessor();
        processor.ProcessPayment(100.00m); // 输出: Paid 100.00 via Credit Card
    }
}

        如果现在需要支持支付宝支付,必须修改 PaymentProcessor 类,增加对支付宝的支持。这种设计违反了开闭原则(对扩展开放,对修改关闭),每次添加新的支付方式都需要修改调用方代码。

        使用接口:

// 定义接口
interface IPayment
{
    void Pay(decimal amount);
}

// 信用卡支付实现
class CreditCardPayment : IPayment
{
    public void Pay(decimal amount)
    {
        Console.WriteLine($"Paid {amount} via Credit Card");
    }
}

// 支付宝支付实现
class AlipayPayment : IPayment
{
    public void Pay(decimal amount)
    {
        Console.WriteLine($"Paid {amount} via Alipay");
    }
}

// 支付处理器
class PaymentProcessor
{
    private IPayment _payment;

    // 通过构造函数注入依赖
    public PaymentProcessor(IPayment payment)
    {
        _payment = payment;
    }

    public void ProcessPayment(decimal amount)
    {
        _payment.Pay(amount);
    }
}

class Program
{
    static void Main(string[] args)
    {
        // 使用信用卡支付
        IPayment creditCardPayment = new CreditCardPayment();
        PaymentProcessor processor1 = new PaymentProcessor(creditCardPayment);
        processor1.ProcessPayment(100.00m); // 输出: Paid 100.00 via Credit Card

        // 使用支付宝支付
        IPayment alipayPayment = new AlipayPayment();
        PaymentProcessor processor2 = new PaymentProcessor(alipayPayment);
        processor2.ProcessPayment(200.00m); // 输出: Paid 200.00 via Alipay
    }
}

         如果需要支持新的支付方式(如微信支付),只需要创建一个新的实现类,而不需要修改PaymentProcessor 或调用方的代码。

        如果使用类,且通过新增方法来实现新功能(如微信支付),而不是修改现有代码,这样会:

        ①、导致类的职责过重,PaymentProcessor 类会随着支付方式的增加而变得臃肿,违反了单一职责原则。

        ②、调用方需要修改。调用方需要知道具体使用哪个支付方法(如 PayByCreditCardPayByAlipayPayByWeChat),如果调用方需要动态选择支付方式,代码会变得复杂。

        ③、难以扩展。如果需要支持更多的支付方式,必须不断修改 PaymentProcessor 类,添加新的方法,这种方式在支付方式较少时可行,但在支付方式较多时会变得难以维护。

1.2 接口和抽象类

特性接口(Interface)抽象类(Abstract Class)
实例化不能实例化不能实例化
字段不能包含字段可以包含字段
多重继承支持多重继承不支持多重继承

2 abstract

        使用abstract关键字定义。

        abstract的作用是提供一种规范或契约,确保派生类具有一致的行为。

2.1 抽象类

        抽象类不能被实例化,只能作为其他类的基类。

        抽象类可以包含抽象方法、具体方法、字段、属性等。

2.2 抽象方法

        抽象方法没有实现,必须在派生类中重写,且要求派生类必须提供具体实现。

        抽象方法只能存在于抽象类中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

可能是这样吧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值