C#中接口设计相关原则
在C#中,接口(Interface)是一种引用类型,它定义了一个契约,指定了一个类必须实现的成员(属性、方法、事件、索引器)。接口不提供这些成员的实现,只指定成员必须按照特定的方式被实现。
1、使用接口隔离原则 (ISP)
将较大的接口划分为更小、更具体的接口,以遵守 ISP,并确保实现类只需要实现它们使用的方法。
// Bad example // A single interface for both lights and thermostats
public interface IDevice
{ void TurnOn(); void TurnOff(); void SetTemperature(int temperature);
} public class SmartLight : IDevice
{ public void TurnOn() { Console.WriteLine("Smart light turned on"); } public void TurnOff() { Console.WriteLine("Smart light turned off"); } public void SetTemperature(int temperature) { // Unsupported operation for a light Console.WriteLine("Cannot set temperature for a light"); }
} // Good example // Interface for a light device
public interface ILight
{ void TurnOn(); void TurnOff();
} // Interface for a thermostat device
public interface IThermostat
{ void SetTemperature(int temperature);
} // A smart light class implementing ILight
public class SmartLight : ILight
{ public void TurnOn() { Console.WriteLine("Smart light turned on"); } public void TurnOff() { Console.WriteLine("Smart light turned off"); }
} // A smart thermostat class implementing IThermostat
public class SmartThermostat : IThermostat
{ public void SetTemperature(int temperature) { Console.WriteLine($"Thermostat set to {temperature}°C"); }
}
2、扩展和可测试性设计
接口在设计时应考虑扩展,以适应未来的更改和增强,而不会破坏现有实现。
// Interface representing a shape
public interface IShape
{ double CalculateArea();
} // Rectangle implementation of the IShape interface
public class Rectangle : IShape
{ public double Width { get; } public double Height { get; } public Rectangle(double width, double height) { Width = width; Height = height; } public double CalculateArea() { return Width \* Height; }
} // Circle implementation of the IShape interface
public class Circle : IShape
{ public double Radius { get; } public Circle(double radius) { Radius = radius; } public double CalculateArea() { return Math.PI * Radius * Radius; }
}
在此示例中:
我们有一个 IShape 接口,它表示一个形状,并使用 CalculateArea() 方法来计算其面积。
我们有实现 IShape 接口的 Rectangle 和 Circle 形状类,每个类都提供自己特定于该形状的 CalculateArea() 方法的实现。
该设计允许通过添加实现 IShape 接口的新形状类来轻松扩展,而无需修改现有代码。例如,如果我们想为 Square 扩展它,我们可以简单地创建一个新的类 Square 使用它自己的 CalculateArea() 方法实现 IShape。
// Square implementation of the IShape interface
public class Square : IShape
{ public double SideLength { get; } public Square(double sideLength) { SideLength = sideLength; } public double CalculateArea() { return SideLength * SideLength; }
}
不可变接口
考虑将接口设计为不可变的,这意味着一旦定义,就无法修改它们。这有助于防止意外更改并确保代码库的稳定性。
// Immutable interface representing coordinates
public interface ICoordinates
{ // Readonly properties for latitude and longitude double Latitude { get; } double Longitude { get; }
} public class Coordinates : ICoordinates
{ public double Latitude { get; } public double Longitude { get; } // Constructor to initialize the latitude and longitude public Coordinates(double latitude, double longitude) { Latitude = latitude; Longitude = longitude; }
}
首选组合而不是继承
在设计接口时,优先考虑组合而不是继承。这促进了代码的重用和灵活性。
// Interface representing a component that can be composed into other classes
public interface IComponent
{ void Process();
} // Example class implementing the IComponent interface
public class Component : IComponent
{ public void Process() { Console.WriteLine("Performing action in Component"); }
} // Example class demonstrating composition
public class CompositeComponent
{ private readonly IComponent _component; public CompositeComponent(IComponent component) { _component = component; } public void Execute() { _component.Process(); }
}
避免接口过载
具有多种方法的重载接口,仅参数的数量或类型不同,可能会导致混淆。请改用不同的方法名称或重构接口。
public interface IVehicle
{ void Start(); void Stop(); void Accelerate(int speed); void Accelerate(double accelerationRate);
}
虽然类中的重载方法是一种常见的做法,但接口中的重载方法可能会导致混淆,并使类实现哪种方法变得不那么清楚。通常,最好对不同的行为使用不同的方法名称,或者在必要时将它们分隔到多个接口中
使用泛型
利用泛型创建灵活且可重用的接口,这些接口可以处理不同类型的接口。这使我们能够编写更通用的代码,并且可以处理更广泛的场景。
// Generic interface for a data access layer
public interface IDataAccessLayer<T>
{ Task<T> GetByIdAsync(int id); Task<IEnumerable<T>> GetAllAsync();
}
版本控制接口
当接口随时间推移而发展时,请考虑对它们进行版本控制,以保持向后兼容性,同时引入新功能。这可以通过接口继承或在接口名称中使用版本控制等技术来实现。
// Interface representing a service for processing orders
public interface IOrderService
{ Task ProcessAsync(Order order);
} // Interface representing a service for processing orders (version 2)
public interface IOrderServiceV2
{ Task ProcessAsync(OrderV2 order);
}
使用协变接口和逆变接口
利用 .NET 中的协方差和逆变,在处理接口实现时允许更灵活的类型转换。
// Covariant interface for reading data
public interface IDataReader<out T>
{ T ReadData();
} // Contravariant interface for writing data
public interface IDataWriter<in T>
{ void WriteData(T data);
}
避免脂肪界面
FAT 接口包含太多成员,这使得它们难以实现和维护。将大型接口拆分为更小、更集中的接口。
// Bad example public interface IDataRepository
{ Task<Data> GetByIdAsync(int id); Task AddAsync(Data data); Task GenerateReportAsync(); Task<bool> ValidateAsync(Data data);
} // Good example // Interface for data retrieval operations
public interface IDataRepository
{ Task<Data> GetByIdAsync(int id); Task CreateAsync(Data data);
} // Interface for data reporting operations
public interface IDataReporting
{ Task GenerateReportAsync();
} // Interface for data validation
public interface IDataValidation
{ Task<bool> ValidateAsync(Data data);
}
使用显式接口实现
当类实现具有相同名称的成员的多个接口时,请使用显式接口实现来消除它们的歧义。这样可以更好地控制接口成员的可见性。
public interface IInterface1
{ void Method();
} public interface IInterface2
{ void Method();
} public class MyClass : IInterface1, IInterface2
{ // Explicit implementation of IInterface1.Method void IInterface1.Method() { Console.WriteLine("IInterface1.Method"); } // Explicit implementation of IInterface2.Method void IInterface2.Method() { Console.WriteLine("IInterface2.Method"); }
}
相关文章:
C#中接口设计相关原则
在C#中,接口(Interface)是一种引用类型,它定义了一个契约,指定了一个类必须实现的成员(属性、方法、事件、索引器)。接口不提供这些成员的实现,只指定成员必须按照特定的方式被实现。…...

Pytorch学习笔记——卷积操作
一、认识卷积操作 卷积操作是一种数学运算,它涉及两个函数:输入函数(通常是图像)和卷积核(也称为滤波器或特征检测器)。卷积核在输入函数上滑动,将核中的每个元素与其覆盖的输入函数区域中的对应…...

探索鸿蒙开发:鸿蒙系统如何引领嵌入式技术革新
嵌入式技术已经成为现代社会不可或缺的一部分。而在这个领域,华为凭借其自主研发的鸿蒙操作系统,正悄然引领着一场技术革新的浪潮。本文将探讨鸿蒙开发的特点、优势以及其对嵌入式技术发展的深远影响。 鸿蒙操作系统的特点 鸿蒙,作为华为推…...

chrome extension插件替换网络请求中的useragent
感觉Chrome商店中的插件不能很好的实现自己想要的效果,那么就来自己动手吧。 本文以百度为例: 一般来说网页请求如下: 当前使用的useragent是User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safar…...
PHP基础【介绍,注释,更改编码,赋值,数据类型】
源码 <?php //单行注释 /* 多行注释 *///通过header()函数发送http头的请求信息用来指定页面的字符集编码 header("Content-type:text/html;Charsetutf-8"); //告诉浏览器,当前页面的内容类型是HTML,并且页面内容使用的是UTF-8编码。//ph…...

ASP.NET小型证券术语解释及翻译系统的设计与开发
摘 要 在系统设计上,综合各种翻译类型网站优缺点,设计出具有任何使用者都可添加术语信息的且只有管理员能够实现术语修改及删除等独特方式的术语查看管理系统。此方式能够使术语量快速增大,并且便于使用者及管理员操作,满足相互…...

硬件知识积累 音频插座的了解,看音频插座的原理图来了解音频插座的引脚。
1. 音频接口 音频插座是一种用于连接音频信号线路的电子元件,常见于音频设备(如音响、耳机、话筒等)中。它的主要作用是将电子信号转化为声音信号,以满足人们对于音乐、电影、游戏等方面的需求。 根据插头形状的不同,音…...

error LNK2001: 无法解析的外部符号 “__declspec(dllimport) public: __cdecl ......
运行程序时,报如上图所示错误,其中一条是: ReflectionProbe.obj : error LNK2001: 无法解析的外部符号 "__declspec(dllimport) public: __cdecl osg::Object::Object(bool)" (__imp_??0ObjectosgQEAA_NZ) 报这个错误一般是因为…...

邮箱Webhook API发送邮件的性能怎么优化?
邮箱Webhook API发送邮件的步骤?如何用邮箱API发信? 随着业务规模的扩大,如何高效地通过邮箱Webhook API发送邮件,成为了许多企业面临的关键问题。下面,AokSend将探讨一些优化邮箱Webhook API发送邮件性能的方法。 邮…...

并发编程实现
一、并行编程 1、Parallel 类 Parallel类是System.Threading.Tasks命名空间中的一个重要类,它提供数据并行和任务并行的高级抽象。 For和ForEach Parallel类下的For和ForEach对应着普通的循环和遍历(普通的for和foreach),但执行时会尝试在多个线程上…...

基于EBAZ4205矿板的图像处理:12图像二值化(阈值可调)
基于EBAZ4205矿板的图像处理:12图像二值化(阈值可调) 我的项目是基于EBAZ4205矿板的阈值可调的图像阈值二值化处理,可以通过按键调整二值化的阈值,key1为阈值加1,key4为阈值减1,key2为阈值加10,key5为阈值…...

人大金仓数据库报com.kingbase8.util.KSQLException: 致命错误: 用户 “SYSTEM“ Password 认证失败
com.kingbase8.util.KSQLException: 致命错误: 用户 “SYSTEM” Password 认证失败 解决办法: 问题在于用户权限只不足,相关配置文件在一般在 /data/sys hba.conf,修改IPV4 local connections选项中的改为trust。...

文件加密软件哪个好?文件加密软件排行榜前十名(好用软件推荐)
文件加密软件哪个好?这是许多个人和企业用户在面临数据保护需求时所关心的问题。随着数字化时代的推进,数据安全问题日益凸显,文件加密软件成为了保护数据安全的重要手段。本文将为您介绍当前市场上排名前十的文件加密软件,帮助您…...

Netty的第一个简单Demo实现
目录 说明需求ClientServer写法总结 实现运行 说明 Netty 的一个练习,使用 Netty 连通 服务端 和 客户端,进行基本的通信。 需求 Client 连接服务端成功后,打印连接成功给服务端发送消息HelloServer Server 客户端连接成功后࿰…...

K8S 哲学 - 服务发现 services
apiVersion: v1 kind: Service metadata:name: deploy-servicelabels:app: deploy-service spec: ports: - port: 80targetPort: 80name: deploy-service-podselector: app: deploy-podtype: NodePort service 的 endPoint (ep) 主机端口分配方式 两…...

Springboot工程创建
目录 一、步骤 二、遇到的问题及解决方案 一、步骤 打开idea,点击文件 ->新建 ->新模块 选择Spring Initializr,并设置相关信息。其中组为域名,如果没有公司,可以默认com.example。点击下一步 蓝色方框部分需要去掉,软件包…...

日本站群服务器的优点以及适合该服务器的业务类型?
日本站群服务器的优点以及适合该服务器的业务类型? 日本站群服务器是指位于日本地区的多个网站共享同一台服务器的架构。这种服务器架构有着诸多优点,使其成为许多企业和网站管理员的首选。以下是日本站群服务器的优点以及适合该服务器的业务类型的分析࿱…...

堆的应用2——TOPK问题
TOPK问题 TOP-K问题:即求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大。 比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等。 情况1——数据量小 对于Top-K问题,能想到的最简单直接的方式就…...
leetcode-5. 最长回文子串
题目描述 给你一个字符串 s,找到 s 中最长的回文子串。 如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。 示例 1: 输入:s "babad" 输出:"bab" 解释:"aba"…...
【Flask 系统教程 1】入门及配置
当你开始学习 Flask 时,了解如何进行基本的配置是非常重要的。Flask 是一个简单而灵活的 Python Web 框架,它允许你快速构建 Web 应用程序,并且易于学习。在这篇博客中,我将介绍如何从零开始进行 Flask 的基础配置,适合…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...

Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...

Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...