C#中接口的显式实现与隐式实现及其相关应用案例

news2024/11/18 6:07:18

C#中接口的显式实现与隐式实现

最近在学习演化一款游戏项目框架时候,框架作者巧妙使用接口中方法的显式实现来变相对接口中方法进行“密封”,增加实现接口的类访问方法的“成本”。

接口的显式实现和隐式实现:

先定义一个接口,接口中有这两个方法。

 public interface ICanSingSong
 {
     void SingJayChow();
     void SingOther();
 }

接下来我们让InterfaceDesignExample 继承该接口。使用常用的隐式实现方法来实现SingJayChow方法,在Start函数中直接可以调用,而使用显式实现的接口方法SingOther,则需要将类的实力转换为接口类型才可以调用。

这样相当于告诉类,ICanSingSong.SingOther()样式就是表明SIngOther是属于ICanSingSong接口中的“私有方法”。调用时候先要将类类型转换为接口。

 public class InterfaceDesignExample : MonoBehaviour,ICanSingSong
 {
     void Start()
     {
         //接口的隐式实现 可以直接调用
         SingJayChow();
         
         //显示调用则需要 准换成接口 调用
         //this.SingOther();   
         (this as ICanSingSong).SingOther();
     }
 
     /// <summary>
     /// 接口的隐式实现
     /// </summary>
     public void SingJayChow()
     {
         Debug.Log("你说家是唯一的城堡,随着稻香一路奔跑~");
     }
 
     /// <summary>
     /// 接口的显式实现
     /// </summary>
     void ICanSingSong.SingOther()
     { 
         Debug.Log("lalalalalalallalaal!");
     }
 }

image

我们这样做的目的之一就是为了增加类对接口中的一些方法的调用成本,和使用“private”修饰有类似效果,降低对方法乱用的可能。

接口-抽象类-子类 使用显式实现接口方法

同样,我们先声明一个接口:

//接口 Application
public interface IApplication
{
    void Start();
    void Update();
    void Destroy();
 
    void Test();
}

抽象类继承该接口,并对生命周期函数进行显式实现,而供子类继承实现的方法为OnXXX

//抽象类
public abstract class Application : IApplication
{
    //不希望子类去访问实现接口的方法
    //使用显式调用
    void IApplication.Start()
    {
    	OnStart();
    }
 
    void IApplication.Update()
    {
    	OnUpdate();
    }
 
    void IApplication.Destroy()
    {
    	OnDestroy();
    }
 
    public void Test()
    {
    Debug.Log("我是测试方法,隐式实现接口的方法,子类可以轻松访问我");
    }
 
    //希望子类的实现的方法
    public abstract void OnStart();
    public abstract void OnUpdate();
    public abstract void OnDestroy();
}

继承抽象类的子类对生命周期函数进行实现:

 //子类
public class SubApplication : Application
{
    public override void OnStart()
    {
        Test();
        //Start(); 情况会发生递归调用 造成堆栈溢出 而此方法使用现实实现 所以在子类中无法访问 避免情况发生
        Debug.Log("OnStart");
    }
 
    public override void OnUpdate()
    {
        Debug.Log("OnUpdate");
    }
 
    public override void OnDestroy()
    {
        Debug.Log("OnDestroy");
    }
}

最后我们调用函数:

//测试调用
//通过接口调用 显示实现的方法
IApplication application = new SubApplication();
 
application.Start();
application.Update();
application.Destroy();
 
//通过类 无法调用显示实现的方法 只能访问使用OnXXXX方法
Application application2 = new SubApplication();
application2.OnStart();
application2.OnUpdate();
application2.OnDestroy();

image

这样我们可以体会到接口作为高抽象层的存在,可以调用子类具体实现的生命周期函数,而子类却无法访问显示实现的接口中“私有”的生命周期函数。

接口--子接口--静态类拓展 实现对接口函数的访问修饰

咳咳~故事开始!

作为一个资深Jay迷,我同样认识一个自称曲库的小精灵【SongLibrary】,它最拿手的三首歌曲是晴天、彩虹和说好不哭.

 //曲库
 public class SongLibrary
 {
     public void SingSunny()
     {
    	 Debug.Log("晴天:刮风这天,我试着握你的手~");
     }
 		//彩虹
     public void SingRainbow()
     {
     	Debug.Log("彩虹:你要离开,我知道很简单~");
     }
 
    public void SingNoCry()
    {
    	Debug.Log("说好不哭:说好不哭让我走~");
    }
}

这个小曲库精灵居住在抽象出的留声机中,我可以通过留声机来和它交流播放对应的歌曲。

public interface ISingAllSong
{
	SongLibrary songLibrary { get; }
}

留声机上有三个按钮,对应播放歌曲,

播放晴天的按钮功能:

抽象出子接口来继承曲库接口,通过静态类拓展来调用曲库中对应方法播放歌曲。

public interface ISingSunny : ISingAllSong
{
 
}
 
//静态类拓展
public static class SingSunnyExtensions
{
    public static void SingSunny(this ISingSunny self)
    {
       self.songLibrary.SingSunny();
    }
}

同样的方式,两个子接口。两个继承子接口的静态类负责调用曲库中的方法:

    //彩虹
    public interface ISingRainbow : ISingAllSong
    {
        
    }
    
    //静态类拓展
    public static class SingRainbowExtensions
    {
        public static void SingRainbow(this ISingRainbow self)
        {
            self.songLibrary.SingRainbow();
        }
    }
    
    //说好不哭
    public interface ISingNoCry : ISingAllSong
    {
        
    }
    
    //静态类拓展
    public static class SingNoCryExtensions
    {
        public static void SingNoCry(this ISingNoCry self)
        {
            self.songLibrary.SingNoCry();
        }
    }

这样我们使用三个静态类来调用留声机【interface】中居住的精灵【class】的方法,实现三个按钮功能。

当我想听歌时候,我只需要按照我的需求,搭配继承对应的子接口即可播放对应的歌曲,不用怕我按下去的是晴天歌曲播放按钮而短路到播放其它的歌曲曲目。

这样保证,拿到对应的子按钮,只能播放对应的歌曲,保证曲目播放的有序性。

public class InterfaceRuleExample : MonoBehaviour
{
    public class OnlySingSunny : ISingSunny
    {
    	SongLibrary ISingAllSong.songLibrary { get; } = new SongLibrary();
    }
 
    public class OnlySingRainbowNoCry : ISingRainbow,ISingNoCry
    {
    	SongLibrary ISingAllSong.songLibrary { get; } = new SongLibrary();
    }
    void Start()
    {
        var onlySingSunny = new OnlySingSunny();
        onlySingSunny.SingSunny();
        //不能访问
        //onlySingSunny.SingRainbow()
        //onlySingSunny.SingNoCry();
 
        var SingRainbowNoCry = new OnlySingRainbowNoCry();
        SingRainbowNoCry.SingRainbow();
        SingRainbowNoCry.SingNoCry();
 
        //无法访问
        //SingRainbowNoCry.SingSUnny();
    }
}

image

总结一下:

使用显示实现方式来对接口中方法进行实现,子类是无法直接调用的,需要将类转换为接口类型才可以调用。

同时如果接口中的方法不想让子类直接调用,可以让抽象类继承接口原生方法,在抽象类中进行方法声明供子类调用,避免子类对抽象层的直接交互。同时,使用静态类拓展来限制子接口对父接口中存在函数方法的访问,保证类对所需方法的规范使用。

也就是说,尽可能不让表层具象的类轻松的访问到抽象层的其它不需要的功能,即类需要什么就继承对应的子接口,实现对应功能即可,多余的功能不要访问。

文章转载自:畅知

原文链接:https://www.cnblogs.com/TonyCode/p/18223431

体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构

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

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

相关文章

11.3 指针和函数

11.3 指针和函数 本节必须掌握的知识点&#xff1a; 指针作为函数的参数 数组作为函数的参数 指针作为函数的返回值 在C语言中&#xff0c;指针的一个重要作用就是作为函数参数使用&#xff0c;本节将介绍这一重要作用。 11.3.1 指针作为函数的参数 实验一百一十三&#xff…

Spring事务管理进阶-rollbackFor propagation

黑马程序员JavaWeb开发教程 文章目录 一、rollbackFor二、propagation2.1 事务传播行为2.2 场景 一、rollbackFor 默认情况下&#xff0c;只有初选RuntimeException才会回滚异常。roolbackFor属性用于控制出现何种异常类型&#xff0c;回滚事务。 二、propagation 用来配置事…

【蓝桥杯国赛】动态规划

“动态规划”在蓝桥杯中的出题类型&#xff0c;主要为两种&#xff0c; 要格外注意&#xff0c;每一次 dp 的迭代更新&#xff0c;都是针对于当前位置下的“所有情况”进行的&#xff0c; 应着眼于当前位置的每一种情况。 类型一&#xff1a;一共有多少种情况&#xff1f; 1…

海外媒体通稿:9个极具创意的旅游业媒体推广案例分享-华媒舍

如今&#xff0c;旅游业正迅速发展&#xff0c;媒体推广成为吸引游客的关键。为了更好地展示旅游目的地&#xff0c;许多创意而富有创新的媒体推广策略应运而生。本文将介绍九个极富创意的旅游业媒体推广案例&#xff0c;为广大从业者带来灵感和借鉴。 1. 视频系列&#xff1a;…

参数设置错误导致的 OOM

参数设置错误导致的 OOM 前言事故分析事故原因事故复盘 前言 2024 年 5 月 10 日 14 时 19 分&#xff0c;C 公司开发人员向 A 公司开发人员反映某开放接口从 2024 年 5 月 10 日 14 时许开始无法访问和使用。该系统为某基础数据接口服务&#xff0c;基于 HTTP 协议进行通信。…

【吊打面试官系列】Java高并发篇 - 什么是线程调度器(Thread Scheduler)和时间分片(TimeSlicing)?

大家好&#xff0c;我是锋哥。今天分享关于 【什么是线程调度器(Thread Scheduler)和时间分片(TimeSlicing)&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; 什么是线程调度器(Thread Scheduler)和时间分片(TimeSlicing)&#xff1f; 线程调度器是一个操作系统服…

【从零开始部署SAM(Segment Anything Model )大模型 3 Ubuntu20 离线部署 C++】

这里是目录 总览环境配置模型准备Moble SAM onnx模型获取Moble SAM pre onnx模型获取 运行cmakelist 运行结果 总览 相比于使用python离线部署SAM大模型&#xff0c;C要麻烦的多&#xff0c;本篇的部署过程主要基于项目&#xff1a;https://github.com/dinglufe/segment-anyth…

数据结构与算法02-排序算法

介绍 排序算法是计算机科学中被广泛研究的一个课题。历时多年&#xff0c;它发展出了数十种算法&#xff0c;这些 算法都着眼于一个问题&#xff1a;如何将一个无序的数字数组整理成升序&#xff1f;先来学习一些“简单排序”&#xff0c;它们很好懂&#xff0c;但效率不如其他…

Git系列:rev-parse 使用技巧

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

vmware workstation 17.0.0 ubuntu删除快照导致无法启动的问题打不开磁盘xxxxxxx或它所依赖的某个快照磁盘

在使用vmware workstation的时候 在我删除多余的快照的时候&#xff0c;发现删除快照后打不开虚拟机了&#xff0c; 提示&#xff1a; 打不开此虚拟磁盘的父磁盘打不开磁盘“D:\Virtual Machines\Ubuntu 64 位\Ubuntu 64 位-000003.vmdk”或它所依赖的某个快照磁盘。模块“Dis…

曾巩,散文的艺术与哲思

曾巩&#xff0c;字子固&#xff0c;世称南丰先生&#xff0c;南丰&#xff08;今江西&#xff09;人&#xff0c;生于北宋真宗天禧三年&#xff08;公元1019年&#xff09;&#xff0c;卒于北宋元丰六年&#xff08;公元1083年&#xff09;&#xff0c;享年64岁。他是中国北宋…

低功耗蓝牙模块在便携式医疗设备上的应用前景

随着科技的不断发展&#xff0c;医疗设备的便携性和智能化已经成为了一种趋势。在这个背景下&#xff0c;低功耗蓝牙模块(Bluetooth Low Energy,简称BLE)作为一种先进的无线通信技术&#xff0c;正逐渐在便携式医疗设备中发挥着越来越重要的作用。本文美迅物联网MesoonRF将探讨…

Debian和ubuntu 嵌入式的系统的 区别

随着开源操作系统的日益流行&#xff0c;Debian和Ubuntu这两个基于Linux的发行版本成为了众多开发者和系统管理员的首选。它们各自拥有独特的优势和特点&#xff0c;那么&#xff0c;在选择时&#xff0c;哪一个更适合你呢&#xff1f;接下来&#xff0c;我们将深入探讨两者的关…

计算机网络——如何保证 TCP 传输的可靠性

TCP 是传输层上的协议&#xff0c;它是可靠的&#xff0c;面向连接的。 概括 1. 设置传输格式&#xff0c;包括分为 TCP 段、使用校验和、使用序列号 2. 数据丢失之后的重传&#xff0c;超时重传、快速重传、SACK 选择确认、D-SACK 重复选择确认 3. 流量控制&#xff0c;控…

python编程:SQLite 管理图片数据库

在本博客中&#xff0c;我们将介绍如何使用 wxPython 和 sqlite3 模块构建一个 GUI 应用程序&#xff0c;该程序可以遍历指定文件夹中的所有图片&#xff0c;并将其信息存储到 SQLite 数据库中。 C:\pythoncode\new\InputImageOFFolderTOSqlite.py 项目简介 我们的目标是创建…

linux可观测性ebpf(一) ----------- 环境搭建

参考书籍 开发环境 Ubuntu 18.04.6 LTS (GNU/Linux 5.4.0-150-generic x86_64) 1.1 下载内核源码 cd /usr/src/ sudo git clone -b v5.4 https://github.com/torvalds/linux.git1.2 下载书中代码 git clone https://github.com/bpftools/linux-observability-with-bpf1.3 编…

Java常用API(三)

一、Arrays类 1.定义 Arrays是一个用于操作数组的工具类。 2.常用方法 1.toString方法 public class Demo {public static void main(String[] args) {//toString 将数组变成字符串int[] arr {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};System.out.println(Arrays.toString(arr));…

arduino 与 nodeMcu 之间的通信

一、前言 当在 arduino 板子处理好了传感器的数据应该发送给远程服务器这时候就需要用 nodeMcu 了&#xff0c;但是怎么把 arduino 的数据发送到 nodeMcu 呢&#xff0c;这就是本文要实现的。 两个板子之间通信很简单&#xff0c;直接使用 arduino IDE 提供的 Serial.println…

Java web应用性能分析之【压测工具ab】

常用的性能测试工具有&#xff1a;JMeter、loadRunner、ab&#xff1b;对于开发人员来说用的多的是免费的Jmeter和ab&#xff0c;对于测试来说可能用收费的商业软件loadRunner多。在这里我们就说说ab压测工具&#xff0c;因为ab基本满足web接口测试要求&#xff0c;jmeter后面再…

详解生成式人工智能的开发过程

回到机器学习的“古老”时代&#xff0c;在您可以使用大型语言模型&#xff08;LLM&#xff09;作为调优模型的基础之前&#xff0c;您基本上必须在所有数据上训练每个可能的机器学习模型&#xff0c;以找到最佳&#xff08;或最不糟糕&#xff09;的拟合。 开发生成式人工智能…