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

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快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构

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

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

相关文章

KotlinConf 2024:深入了解Kotlin Multiplatform (KMP)

KotlinConf 2024&#xff1a;深入了解Kotlin Multiplatform (KMP) 在近期的Google I/O大会上&#xff0c;我们推荐了Kotlin Multiplatform (KMP)用于跨移动、网页、服务器和桌面平台共享业务逻辑&#xff0c;并在Google Workspace中采用了KMP。紧接着&#xff0c;KotlinConf 2…

豆包浏览器插件会造成code标签内容无法正常显示

启用状态&#xff1a;页面的代码会显示不正常 禁用后&#xff0c;正常显示 害得我重置浏览器设置&#xff0c;一个个测试

CentOS7.9部署安装OpenGauss 5.0.2企业版

1、更新系统: yum update -y 2、更改主机名&#xff1a; hostnamectl set-hostname opendb01 3、关闭透明页&#xff1a; echo never > /sys/kernel/mm/transparent_hugepage/enabled echo never > /sys/kernel/mm/transparent_hugepage/defrag# 加入开机自启动 echo …

微信小程序使用echarts

思路 五个tab公用一个柱状图组件切换tab以及切换时间改变数据&#xff0c;传入子组件&#xff0c;子组件监听数据重新更新点击柱状图显示具体数值每个时间点有两个柱子&#xff08;高压和低压&#xff09;&#xff0c;柱状图显示高压的最大值到最小值的范围除了血压其余只有一…

【Epoch,Batch,Iteration】深度学习模型训练相关基础概念光速理解!

&#x1f525;模型训练相关基础概念&#xff01; Epoch: 一次 epoch 代表整个训练数据集已经被完整地送入神经网络进行了一轮训练。通常&#xff0c;模型需要多次 epoch 才能充分学习数据集中的模式。Batch: 由于数据集可能过大&#xff0c;无法一次性全部加载到内存中进行训练…

【前端】Mac安装node14教程

在macOS上安装Node.js版本14.x的步骤如下&#xff1a; 打开终端。 使用Node Version Manager (nvm)安装Node.js。如果你还没有安装nvm&#xff0c;可以使用以下命令安装&#xff1a; curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash 然后关…

LAMP分布式安全方案搭建网页 (LinuxCentOS7+Apache+Mariadb+PHP)包括服务端口及防火墙规则配置

目录 一、实验目的 二、设计方案及规划 三、实验内容及步骤 &#xff08;1&#xff09;实验前基础配置 &#xff08;2&#xff09;Test配置&#xff0c;安装Firefox浏览器和图形界面 &#xff08;3&#xff09;Web安装Apache &#xff08;4&#xff09;Database安装Mari…

2.4 Docker部署JDK

2.4 Docker部署JDK jdk17部署&#xff08;自定义镜像&#xff09; 1.在官网上下载jdk-17_linux-x64_bin.tar.gz&#xff0c;并安装到/usr/local目录下 cd /usr/local2.创建Dockerfile vim Dockerfile# 基于官方的Ubuntu 20.04镜像作为基础镜像 FROM ubuntu:20.04# 设置环境…

瑞吉外卖项目学习笔记(二)后台系统的员工管理业务开发

一、完善登录功能 1.1 问题分析 1.2 代码实现 package com.itheima.reggie.filter;//这是一个过滤器类 //登录检查过滤器import com.alibaba.fastjson.JSON; import com.itheima.reggie.common.R; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf…

探索k8s集群的存储卷 emptyDir hostPath nfs

目录 一 含义 查看支持的存储卷类型 emptyDir存储卷 1.1 特点 1.2 用途 1.3部署 二、hostPath存储卷 一 含义 容器磁盘上的文件的生命周期是短暂的&#xff0c;这就使得在容器中运行重要应用时会出现一些问题。首先&#xff0c;当容器崩溃时&#xff0c;kubelet 会重…

磁盘配额的具体操作

磁盘配额&#xff1a; linux的磁盘空间有两个方面&#xff1a;第一个是物理空间&#xff0c;也就是磁盘的容量 第二个inode号耗尽&#xff0c;也无法写入 linux根分区&#xff1a;根分区的空间完全耗尽&#xff0c;服务程序崩溃&#xff0c;系统也无法启动了。 为了防止有人…

师彼长技以助己(2)产品思维

师彼长技以助己&#xff08;2&#xff09;产品思维 前言 我把产品思维称之为&#xff1a;人生底层的能力以及蹉跎别人还蹉跎自己的能力&#xff0c;前者说明你应该具备良好产品思维原因&#xff0c;后者是你没有好的产品思维去做产品带来的灾难。 人欲即天理 请大家谈谈看到这…

错误 0x80070570:文件或目录损坏且无法读取/无法访问[拒绝访问]-解决方法

1.起因&#xff1a;在挪动&#xff35;盘文件时&#xff0c;出现无法移动的报错提示&#xff1a; and无法访问[拒绝访问]: 2.原因&#xff3b;大多是胡乱拔出&#xff35;盘&#xff3d; &#xff3b;来自0x80070570 文件或目录损坏且无法读取 CHKDSK 修复方法-CSDN博客&#…

【介绍下SCSS的基本使用】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

【AI应用开发框架】应用phidata快速构建你的智能体(如个人知识库、自动选股等)

1.phidata是什么&#xff1f; AI APP开发框架&#xff0c;基于此框架可快速搭建智能体或智能助手以实现记忆、知识库及工具使用等功能。 2.框架是怎样的&#xff1f; 3.为什么选择phidata&#xff1f; 问题&#xff1a;LLMs 的上下文有限&#xff0c;无法执行具体动作 解决…

[数据集][目标检测]猫狗检测数据集VOC+YOLO格式8291张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;8291 标注数量(xml文件个数)&#xff1a;8291 标注数量(txt文件个数)&#xff1a;8291 标注…

LeetCode-131 分割回文串

LeetCode-131 分割回文串 题目描述解题思路C 代码 题目描述 给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个子串都是 回文串。返回 s 所有可能的分割方案。 示例 1&#xff1a; 输入&#xff1a;s “aab” 输出&#xff1a;[[“a”,“a”,“b”],…

1.8k Star!RAGApp:在任何企业中使用 Agentic RAG 的最简单方法!

原文链接&#xff1a;&#xff08;更好排版、视频播放、社群交流、最新AI开源项目、AI工具分享都在这个公众号&#xff01;&#xff09; 1.8k Star&#xff01;RAGApp&#xff1a;在任何企业中使用 Agentic RAG 的最简单方法&#xff01; &#x1f31f;在任何企业中使用 Agent…

大数据信用报告分析和评估有什么意义

大数据信用这个词在现在已经是很常见的了&#xff0c;只要是申贷的朋友对它就不陌生&#xff0c;在明面上的信用资质刚刚满足审核要求&#xff0c;但又要把控风险的时候&#xff0c;这个时候大数据信用就会作为风控机构交叉核查的重要依据。那你知道大数据信用报告分析和评估有…

二、线性回归模型

目录 一、线性回归 1.模型示例 2.代码实验&#xff08;C1_W1_Lab03_Model_Representation&#xff09; (1).工具使用 (2).问题描述-房价预测 (3).输入数据 (4).绘制数据集坐标点 (5).建模构造函数 二、代价函数&#xff08;Cost function&#xff09; 1.解释一下概念…