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.mzph.cn/news/762044.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

笔试总结01

1、spring原理 1、spring原理 spring的最大作用ioc/di,将类与类的依赖关系写在配置文件中&#xff0c;程序在运行时根据配置文件动态加载依赖的类&#xff0c;降低的类与类之间的藕合度。它的原理是在applicationContext.xml加入bean标记,在bean标记中通过class属性说明具体类…

vue3+threejs新手从零开发卡牌游戏(二):初始化场景

在删掉初始化中一些没用的代码后&#xff0c;在views目录下新建game文件夹&#xff0c;在里面新建一个index.vue&#xff0c;这里就当成游戏的主入口。 目录结构如下&#xff1a; 下面开始尝试创建场景&#xff1a; 一、添加一个div作为threejs的画布对象&#xff0c;之后整个…

ubuntu - 编译 linphone-sdk

业务需求需要定制sdk&#xff0c;首先声明我们需要的是在Android4.4上跑的sdk&#xff0c;因此本次编译的sdk最低支持为19&#xff08;不同版本需要的环境不一致&#xff09;&#xff0c;编译过程较容易&#xff0c;难点在于环境配置 环境准备 Ubuntu 18.04.6 android-sdk_r24.…

mysql分页查询多用GitCode平台

目录 一、在GitCode平台AI搜索结果&#xff08;这个更优&#xff09; 二、在百度搜索输入“mysql Java分页查询”的输出结果&#xff1a; 三、推荐的文章 四、GitCode的使用 1&#xff09;如搜索jdk11可以直接下载jdk11的包 2&#xff09;搜索开源项目 3&#xff09;如搜…

步进电机驱动器的接线与使用(接线详细)

今天小编就来继续学习与使用步行电机的学习&#xff0c;如果位置对你有帮助&#xff0c;评论收藏&#xff0c;点赞一下 步进电机驱动器 步进电机驱动器是一种专用于控制步进电机的电子设备&#xff0c;用于控制步进电机的转动和位置。步进电机是一种将电信号转换为机械运动的电…

Compose UI 之 Segmented buttons 分段按钮

Segmented buttons SegmentedButton 是一种分段式按钮组件,它允许用户在一组相关的选项中选择一个或几个。 上图中:① 单选的分段式按钮。② 多选的分段式按钮。 分段式按钮的几个特点: 分段式按钮是带有状态的按钮,又有单选和多选之分。 从设计上将,不论是单选或是多选…

【GPT概念-03】:人工智能中的注意力机制

说明 注意力机制生成分数&#xff08;通常使用输入函数&#xff09;&#xff0c;确定对每个数据部分的关注程度。这些分数用于创建输入的加权总和&#xff0c;该总和馈送到下一个网络层。这允许模型捕获数据中的上下文和关系&#xff0c;而传统的固定序列处理方法可能会遗漏这…

虚拟机扩展:虚拟机快照

虚拟机快照 在学习阶段我们无法避免的可能损坏Linux操作系统。如果损坏的话&#xff0c;重新安装一个Linux操作系统就会十分麻烦。 那我们就可以通过快照将当前虚拟机的状态保存下来&#xff0c;在以后系统损坏时通过快照恢复虚拟机到保存的状态。 制作并还原快照 在VMware …

SAP HCM 0008信息类型间接评估与直接评估

如果在间接评估模块输入就是间接评估&#xff08;tarif是读取下图中的数据 a代表不需要输入工资项&#xff0c;b表示需要找工资相&#xff09; 不输入就是直接评估需要客户自己输入数字 第2个情况 summe求和 &#xff08;比如在0008中输入9000与9001 那么自动求出9002工资项数…

C# WPF编程-布局

C# WPF编程-布局 布局WPF布局原则布局过程布局容器布局属性Border控件StackPanel布局WrapPanel布局DockPanel布局Grid布局UniformGrid布局Canvas布局 布局 WPF布局原则 WPF窗口只能包含单个元素。为在WPF窗口中放置多个元素并创建更贴近实用的用户界面&#xff0c;需要在窗口…

SpringBoot项目如何打包成war包,并部署在tomcat上运行

项目场景&#xff1a; 正常情况下&#xff0c;我们开发 SpringBoot 项目&#xff0c;由于内置了Tomcat&#xff0c;所以项目可以直接启动&#xff0c;部署到服务器的时候&#xff0c;直接打成 jar 包&#xff0c;就可以运行了。 有时我们会需要打包成 war 包&#xff0c;放入外…

Redis进阶(持久化、复制、集群、多线程、缓存)

Redis进阶 1.Redis持久化1.1 什么是Redis持久化&#xff1f;为什么需要持久化&#xff1f;1.2 Redis持久化方式——RDB(Redis DataBase)1.2.1 什么是RDB&#xff1f;1.2.2 备份文件位置1.2.3 触发RDB的方式1.2.3.1 自动触发1.2.3.2 手动触发1.2.3.3 其他触发方式 1.2.4 RDB优缺…

【GPT概念04】仅解码器(only decode)模型的解码策略

一、说明 在我之前的博客中&#xff0c;我们研究了关于生成式预训练转换器的整个概述&#xff0c;以及一篇关于生成式预训练转换器&#xff08;GPT&#xff09;的博客——预训练、微调和不同的用例应用。现在让我们看看所有仅解码器模型的解码策略是什么。 二、解码策略 在之前…

【Linux】多线程编程基础

&#x1f4bb;文章目录 &#x1f4c4;前言&#x1f33a;linux线程基础线程的概念线程的优缺点线程与进程的区别 线程的创建 &#x1f33b;linux线程冲突概念互斥锁函数介绍加锁的缺点 &#x1f4d3;总结 &#x1f4c4;前言 无论你是否为程序员&#xff0c;相信多线程这个词汇应…

量子计算机

近日&#xff0c;在AWS re&#xff1a;Invent全球大会上&#xff0c;亚马逊官宣AWS三箭齐发量子计算组合拳&#xff1a;Braket、AWS量子计算中心和量子解决方案实验室。 随着亚马逊的强势入局&#xff0c;加上此前鼓吹量子霸权的谷歌、起步最早的IBM、暗自发力的微软&#xff…

react-jsx

react04 jsx语法 - 01 基础知识&#xff1a; jsx javascript xml(html) 把js和heml标签混合到一起 react视图编写及构建的简要流程 &#xff1a; 如何在react中使vs code支持格式化和快捷键提示&#xff1a;1, 2,修改文件后缀为jsx&#xff0c;因为webpack的打包规则中可以…

如何通过idea搭建一个SpringBoot的Web项目(最基础版)

通过idea搭建一个SpringBoot的Web项目 文章目录 通过idea搭建一个SpringBoot的Web项目一、打开idea&#xff0c;找到 create new project二、创建方式三、配置项目依赖四、新建项目模块五、总结 一、打开idea&#xff0c;找到 create new project 方式1 方式2 二、创建方式 新…

马斯克开源Grok-1

Grok-1是由马斯克AI创企xAI发布的第一代大语言模型&#xff0c;它以其巨大的参数量——高达3140亿&#xff0c;引起了全球范围内的广泛关注。这一参数量远超其他知名模型&#xff0c;如OpenAI的GPT-3.5&#xff0c;后者仅有1750亿参数。在2024年3月17日&#xff0c;马斯克宣布将…

【jvm】jinfo使用

jinfo介绍 jinfo 是一个命令行工具&#xff0c;用于查看和修改 Java 虚拟机&#xff08;JVM&#xff09;的配置参数。它通常用于调试和性能调优。 使用 jinfo 命令&#xff0c;你可以查看当前 JVM 的配置参数&#xff0c;包括堆大小、线程数、垃圾回收器类型等。此外&#xf…

天翼云防火墙配置端口转换案例

环境: 天翼云 云墙 问题描述: 天翼云防火墙配置端口转换案例 云主机192.168.10.9:2231 解决方案: 1.先登入云墙 可以从控制中心登入不用再输入密码 2.新建对象和端口 192.168.10.9:2231 3.到弹性IP这选个公网IP 记住弹性IP和后面虚拟IP 4.新建 目的NAT,按原有复制…