C#探索之路基础篇(2):接口Interface的概念、实现、应用范围

文章目录

      • 1 概念
      • 2 示例代码:
        • 2.1 简单接口的实现
        • 2.2 简单的使用接口
        • 2.3 使用接口呈现多态性
        • 2.4 通过接口实现一个数组迭代器
        • 2.5 通过接口来实现松耦合的关系
        • 2.6 使用接口实现可扩展、便利性
      • 3 使用范围与时机
      • 4 注意事项

不知道大家在学习的过程中,有没有反复的接触到接口这个概念。

但如果在没有经常使用接口的情况下, 我相信大家可能在接口的设计和使用上有点陌生和茫然。

特别容易出现,我知道接口是什么,也知道它的作用是什么,但是真让你写功能的时候去使用上接口时,往往就不知所措了。

1 概念

在C#中,接口(Interface)是一种抽象类型,它定义了一组方法、属性、索引器和事件的契约,但并不提供这些成员的具体实现。接口定义了对象应该具有的行为,但不指定每个行为的具体实现方式。

接口在C#中有以下几个关键特点和用途:

  1. 抽象行为定义: 接口定义了类应该具有的行为,但不关心具体的实现细节。通过接口,你可以定义一组方法、属性等,但是具体的实现由实现该接口的类来完成。

  2. 实现多态性: 接口提供了一种多态的实现方式。**多个类可以实现同一个接口,从而在不同的上下文中使用这些类,而不需要关心它们的具体类型。**这种多态性的使用可以增加代码的灵活性和可维护性。

  3. 解耦合: 接口有助于减少类之间的耦合度。当类通过接口进行通信时,它们只需要知道接口定义的契约,而不需要知道具体的实现细节。这样可以使得系统更易于扩展和修改。

  4. 实现约束: 接口可以用来约束类的行为。通过实现特定的接口,可以确保类具有某些特定的行为或功能,这有助于提高代码的可靠性和可预测性。

  5. 模块化设计: 使用接口可以将系统划分为模块化的组件,每个组件通过接口定义自己的行为,从而实现更好的代码组织和管理。

举例来说,如果你在一个图形界面应用程序中需要定义各种形状(如矩形、圆形等)的绘制行为,你可以定义一个IShape接口,包含一个Draw方法。然后,不同的形状类可以实现这个接口,并提供自己的Draw方法实现,从而实现各种形状的绘制。

总之,接口是一种非常有用的工具,可以帮助你实现代码的抽象、多态、解耦合和模块化,从而提高代码的质量、可维护性和可扩展性。

2 示例代码:

2.1 简单接口的实现
//声明一个简单的接口
interface IAnimal
{
    void Eat();
}

接口本身是一种约束,当这个接口没有约束任何类的时候,声明接口也就没有意义了。

2.2 简单的使用接口
//声明一个简单的接口
interface IAnimal
{
    string Name { get; }
    void Eat();
}

//使用接口去约束类
class Dog : IAnimal
{

    public string Name => GetName();

    public void Eat()
    {
        Console.WriteLine($"{Name}吃东西了");
    }

    public string GetName()
    {
        return "狗";
    }
}


class Program
{
    static void Main(string[] args)
    {

        Dog dog = new Dog();
        Console.WriteLine(dog.Name);
        dog.Eat();
    }
}

2.3 使用接口呈现多态性
// 定义日志记录器接口
public interface ILogger
{
    void Log(string message);
}

// 文件日志记录器实现
public class FileLogger : ILogger
{
    public void Log(string message)
    {
        // 将日志信息写入文件
        Console.WriteLine($"[File] {message}");
    }
}

// 控制台日志记录器实现
public class ConsoleLogger : ILogger
{
    public void Log(string message)
    {
        // 在控制台输出日志信息
        Console.WriteLine($"[Console] {message}");
    }
}

// 使用示例
class Program
{
    static void Main(string[] args)
    {
        ILogger logger = new FileLogger();
        logger.Log("This is a log message."); // 输出:[File] This is a log message.

        logger = new ConsoleLogger();
        logger.Log("This is another log message."); // 输出:[Console] This is another log message.
    }
}

在这个示例中,接口 ILogger 定义了日志记录器的契约,而 FileLoggerConsoleLogger 分别提供了不同的日志记录方式。通过接口,我们可以轻松地切换不同的日志记录器实现。

2.4 通过接口实现一个数组迭代器
// 定义迭代器接口
public interface IIterator<T>
{
    T Next();
    bool HasNext();
}

// 数组迭代器实现
public class ArrayIterator<T> : IIterator<T>
{
    private T[] _array;
    private int _index = 0;

    public ArrayIterator(T[] array)
    {
        _array = array;
    }

    public T Next()
    {
        return _array[_index++];
    }

    public bool HasNext()
    {
        return _index < _array.Length;
    }
}

// 使用示例
class Program
{
    static void Main(string[] args)
    {
        int[] numbers = { 1, 2, 3, 4, 5 };
        IIterator<int> iterator = new ArrayIterator<int>(numbers);

        while (iterator.HasNext())
        {
            Console.WriteLine(iterator.Next());
        }
    }
}

在这个示例中,接口 IIterator<T> 定义了迭代器的契约,而 ArrayIterator<T> 则提供了数组迭代器的实现。

2.5 通过接口来实现松耦合的关系
public interface IOrderProcessor
{
    void ProcessOrder(Order order);
}

// 网上商店订单处理器实现
public class OnlineStoreOrderProcessor : IOrderProcessor
{
    public void ProcessOrder(Order order)
    {
        // 处理网上商店订单
        Console.WriteLine($"处理在线商店订单{order.ProductName}");
    }
}

// 实体商店订单处理器实现
public class PhysicalStoreOrderProcessor : IOrderProcessor
{
    public void ProcessOrder(Order order)
    {
        // 处理实体商店订单
        Console.WriteLine($"处理实体店订单 {order.ProductName}");
    }
}

// 订单类
public class Order
{
    public string ProductName { get; set; }
    // 其他订单相关信息
}

// 使用示例
class Program
{
    static void Main(string[] args)
    {
        IOrderProcessor onlineStoreProcessor = new OnlineStoreOrderProcessor();
        IOrderProcessor physicalStoreProcessor = new PhysicalStoreOrderProcessor();

        Order onlineOrder = new Order { ProductName = "笔记本电脑" };
        onlineStoreProcessor.ProcessOrder(onlineOrder); // 输出:处理笔记本电脑的在线商店订单

        Order physicalOrder = new Order { ProductName = "书" };
        physicalStoreProcessor.ProcessOrder(physicalOrder); // 输出:处理书籍的实体店订单
    }
}

2.6 使用接口实现可扩展、便利性
public interface IOrderProcessor
{
    void ProcessOrder(Order order);
}

// 支付接口
public interface IPaymentProcessor
{
    void ProcessPayment(Order order);
}

// 网上商店订单处理器实现
public class OnlineStoreOrderProcessor : IOrderProcessor
{
    private readonly IPaymentProcessor _paymentProcessor;//我们在一个订单处理器类中加入了支付接口,即给订单处理器添加支付的功能(接口,不关注实现)

    public OnlineStoreOrderProcessor(IPaymentProcessor paymentProcessor)
    {
        _paymentProcessor = paymentProcessor;
    }

    public void ProcessOrder(Order order)
    {
        // 处理网上商店订单
        Console.WriteLine($"处理在线商店订单 {order.ProductName}");
        _paymentProcessor.ProcessPayment(order);
    }
}

// 网上商店支付处理器实现
public class OnlineStorePaymentProcessor : IPaymentProcessor
{
    public void ProcessPayment(Order order)
    {
        // 处理网上商店支付
        Console.WriteLine($"处理在线商店订单的付款: {order.OrderId}");
    }
}

// 订单类
public class Order
{
    public int OrderId { get; set; }
    public string ProductName { get; set; }
}

// 使用示例
class Program
{
    static void Main(string[] args)
    {
        //创建了网上商店支付处理器(处理器中中包含支付接口)
        Console.WriteLine("创建了网上商店支付处理器(处理器中中包含支付接口)");
        IPaymentProcessor paymentProcessor = new OnlineStorePaymentProcessor();

        //创建订单处理器(在声明中,创建订单->要求我们传入一个支付接口)
        Console.WriteLine("创建订单处理器(在声明中,创建订单->要求我们传入一个支付接口)");
        IOrderProcessor onlineStoreProcessor = new OnlineStoreOrderProcessor(paymentProcessor);

        //创建一个最简单的订单
        Console.WriteLine("创建一个最简单的订单");
        Order onlineOrder = new Order { OrderId = 123, ProductName = "Laptop" };
        //通过订单处理处理器->处理对应的订单->此时我们不需要传入支付接口,
        //因为支付接口旨在提供给订单处理器,而非订单。而订单处理器中要求我们指定对应的订单是什么
        Console.WriteLine("通过订单处理处理器->处理对应的订单->此时我们不需要传入支付接口,");
        Console.WriteLine("因为支付接口旨在提供给订单处理器,而非订单。而订单处理器中要求我们指定对应的订单是什么");
        onlineStoreProcessor.ProcessOrder(onlineOrder);
        // 输出:
        // 处理笔记本电脑的在线商店订单
        // 处理在线商店订单的付款:123
    }
}

3 使用范围与时机

1、需求要求我们实现多态

2、当前类的关系耦合关系比较严重,要求去实现解耦

3、实现约束

4、模块化的设计、框架过程中的设计

5、实现设计模式(为了提高代码的可读性、可维护性、可扩展性)

4 注意事项

在使用接口时,有一些注意事项需要考虑:

  1. 接口设计要合理:接口应该根据需求进行设计,具有清晰的定义和明确的目的。接口设计应该简洁、一致,避免定义过于复杂或冗余的接口。

  2. 遵循接口设计原则:遵循接口设计原则,如单一职责原则(一个接口应该只有一个目的)、依赖倒置原则(高层模块不应该依赖于低层模块,两者都应该依赖于抽象)、开闭原则(接口应该是开放的,但是关闭修改)等,可以帮助你设计出更好的接口。

  3. 命名规范:接口的命名应该清晰明了,能够准确地描述其所表示的功能或行为。一般来说,接口名称应该以大写字母 “I” 开头,后面跟着描述性的名称。

  4. 避免过度使用接口:不要过度使用接口,否则可能会导致代码过于复杂和冗余。只有在需要实现多态性、解耦合等特性时才使用接口,否则可以考虑使用抽象类或其他方式来实现需求。

  5. 避免接口膨胀:不要定义过多的接口,否则可能会导致接口膨胀问题。如果接口过于庞大,考虑将其拆分成多个更小的接口,以提高代码的可维护性和可读性。

  6. 接口版本管理:在项目中使用接口时,要考虑接口的版本管理。当接口发生变化时,要确保对接口的修改不会影响到已有的实现类,并且要及时通知和更新依赖于该接口的其他模块。

  7. 文档和注释:为接口提供清晰的文档和注释,描述接口的用途、约束和使用方式,以便其他开发人员能够正确地使用接口。

  8. 避免过度设计:有的时候只是一个很小的功能,并且从需求的角度出发,是一次性的使用时,就没有太大的必要一定要抽象成一个接口出来用于使用。

总的来说,合理设计和使用接口可以提高代码的灵活性、可维护性和可扩展性,但在使用时需要注意上述事项,以避免出现不必要的问题。

在这里插入图片描述

公众号:平平无奇代码猴
也可以搜索:Jackiie_wang 公众号,欢迎大家关注!欢迎催更!留言!

作者:ProMer_Wang

链接:https://blog.csdn.net/qq_43801020/article/details/136925776

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/476715.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AI原生安全 亚信安全首个“人工智能安全实用手册”开放阅览

不断涌现的AI技术新应用和大模型技术革新&#xff0c;让我们感叹从没有像今天这样&#xff0c;离人工智能的未来如此之近。 追逐AI原生&#xff1f;企业组织基于并利用大模型技术探索和开发AI应用的无限可能&#xff0c;迎接生产与业务模式的全面的革新。 我们更应关心AI安全原…

机器学习——决策树(四)后剪枝

观前提示&#xff1a;这是本人决策树相关的第四篇博文&#xff0c;前3篇的内容如下&#xff1a; 1、建造训练集的决策树【完成结点类编写和建树过程】 2、用验证集评估模型、选出泛化较好的数据划分方式训练模型 3、预剪枝 读者可根据需要从上方《机器学习》专栏中查阅对应…

【论文笔记】RobotGPT: Robot Manipulation Learning From ChatGPT

【论文笔记】RobotGPT: Robot Manipulation Learning From ChatGPT 文章目录 【论文笔记】RobotGPT: Robot Manipulation Learning From ChatGPTAbstractI. INTRODUCTIONII. RELATED WORK1. LLMs for Robotics2. Robot Learning III. METHODOLOGY1. ChatGPT Prompts for Robot …

基于Python3的数据结构与算法 - 16 链表

目录 链表 1. 创建链表 2. 链表的插入和删除 3. 双链表 4. 链表总结 链表 链表是由一系列节点组成的元素集合。每个节点包含两部分&#xff0c;数据域item和指向下一个节点得指针next。通过节点之间的相互连接&#xff0c;最终串联成一个链表。 class Node:def __init…

数据结构——循环队列的实现

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#x…

Python 小而精Web开发框架Flask精通指南

文章目录 Flask 简介说明Flask 核心依赖Flask 常用扩展Flask 快速启动工作流程代码示例Flask 快速启动控制台Flask 快速启动效果 Flask 启动参数Flask 路由定义Flask 支持的 HTTP 请求方式&#xff1a;路由装饰器中的参数 Flask 路由参数Flask 路由蓝图路由蓝图的优点路由蓝图的…

痛失offer的八股

java面试八股 mysql篇&#xff1a; 事物的性质&#xff1a; 事物的性质有acid四特性。 a&#xff1a;automic&#xff0c;原子性&#xff0c;要么全部成功&#xff0c;要么全部失败&#xff0c;mysql的undolog&#xff0c;事物在执行的时候&#xff0c;mysql会进行一个快照读…

获取KEGG通路的基因列表 做单细胞GSEA、GSVA分析

使用KEGG通路的基因列表进行单细胞GSEA GSVA分析的过程&#xff0c;我们需要遵循以下步骤&#xff1a; 获取KEGG通路的基因列表&#xff1a;这通常涉及使用专门的R包&#xff0c;如KEGGREST或biomaRt&#xff0c;来查询KEGG数据库并检索特定通路的基因列表。 准备单细胞表达数…

详解JS原型与原型链的关系

1、构造函数原型prototype (1)、构造函数通过原型分配的函数是所有对象所共享的&#xff1b; (2)、JavaScript规定&#xff0c;每一个构造函数都有一个prototype属性&#xff0c;指向另一个对象&#xff1b; (3)、注意这个prototype就是一个对象&#xff0c;这个对象的所有属性…

Scikit-Learn逻辑回归(二)

Scikit-Learn逻辑回归二&#xff1a;多项式与正则化 1、多项式回归回顾1.1、逻辑回归为什么要使用多项式1.2、多项式回归及原理 2、逻辑回归与多项式 1、多项式回归回顾 本文接上篇&#xff1a;Scikit-Learn逻辑回归(一) 上篇中&#xff0c;我们详细介绍了逻辑回归的概念、原理…

使用 React antd 的ProFormSelect组件 搜索查询 多选的写法

使用 React antd 的ProFormSelect组件 搜索查询 多选的写法 需求&#xff1a;需要一个搜索框&#xff0c;可以选择员工&#xff0c;&#xff08;员工人数多无法一次性获取&#xff0c;全部放入options中&#xff09;&#xff0c;所以需要使用搜索功能&#xff0c;而且是可以多…

XR“黑话”

MTP&#xff08;Motion-To-Photon Latency&#xff09;&#xff1a;实际人体发生运动到图像显示到屏幕上的时间延迟。早期一些vr产生晕动症的主要原因。 ATW&#xff08;Asynchronous Timewarp&#xff09;&#xff1a;主要解决两个问题&#xff0c;一是延迟&#xff0c;二是补…

CSS弹性盒模型(学习笔记)

一、厂商前缀 1.1 作用 解决浏览器对C3新特性的兼容&#xff0c;不同的浏览器厂商&#xff0c;定义了自己的厂商前缀 1.2 语法 浏览器 厂商前缀内核(渲染引擎)&#xff1a;解析htmlcssjs谷歌 -webkit-blink苹果-webkit-webkit欧朋-o-blink火狐 -moz-geckoIE-ms- trid…

OpenCV4.9.0开源计算机视觉库安装教程

返回&#xff1a;OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 引言&#xff1a;OpenCV系列文章中的安装部分今天全部完成了&#xff0c;为了读者更方便阅读&#xff0c;大家可以按下列索引前往&#xff0c;成文较为仓促有错漏在所难免&#xff0c;欢迎大家指正…

服务器运行一段时间后

自己记录一下。 一、查看目录占用情况 df -h 命令查看磁盘空间 du -ah --max-depth=1 / 查看根目录下各个文件占用情况 二、mysql日志清空 这个日志是可以清空的 echo > /usr/local/mysql/data/syzl-db2.log #将文件清空 说明: 这个文件这么大是因为,开启 …

将OpenCV与gdb驱动的IDE结合使用

返回&#xff1a;OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇&#xff1a;OpenCV4.9.0开源计算机视觉库在 Linux 中安装 下一篇&#xff1a;将OpenCV与gcc和CMake结合使用 ​ 能力 这个漂亮的打印机可以显示元素类型、、标志is_continuous和is_subm…

微信小程序分销返佣模式--小程序1-3级分销插件--小程序分销--

团购小程序是一种基于社区团购模式的电商平台&#xff0c;主要面向社区居民用户。 如果你想要开发一款分销团购小程序可以参考以下功能需求进行开发制作。 1、用户注册和登录 提供用户注册和登录功能&#xff0c;使用户能够创建和管理他们的账户。 2、会员管理 包括会员注…

springboot网站开发-诡异的static/images读取故障

springboot网站开发-诡异的static/images读取故障!我在本地环境测试代码&#xff0c;一切正常。可以读取到该路径下的图片模板&#xff0c;正常生成图片存储在本地D盘下面的文件夹。但是改成服务器linux环境后就不行了。打包发布后&#xff0c;死活读取不到图片模板。 这个故障…

HTML(一)

一、网页 1.1 什么是网页 网站是指在因特网上根据一定的规则&#xff0c;使用 HTML 等制作的用于展示特定内容相关的网页集合。 网页是网站中的一“页”&#xff0c;通常是 HTML 格式的文件&#xff0c;它要通过浏览器来阅读。 网页是构成网站的基本元素&#xff0c;它通常由…

基于python+vue智慧农业小程序flask-django-php-nodejs

传统智慧农业采取了人工的管理方法&#xff0c;但这种管理方法存在着许多弊端&#xff0c;比如效率低下、安全性低以及信息传输的不准确等&#xff0c;同时由于智慧农业中会形成众多的个人文档和信息系统数据&#xff0c;通过人工方法对知识科普、土壤信息、水质信息、购物商城…