反射、依赖注入

news2024/11/24 21:25:40

特性和依赖注入都是基于反射的,同时反射一般和接口配合着使用。

接口隔离原则

接口隔离原则:主张应该把客户端对一个类的需求分解成更小、更具体的接口,而不是提供一个包含所有功能的大接口。 

接口中的需求是:乙方不能少给,且甲方不能多要,但甲方不能多要是软性的。所以容易导致违反接口隔离原则。

常见的违反接口隔离原则的情况

情况一

1、为满足少数客户的需求而创建了一个包含众多方法的庞大接口,导致其他不需要某些方法的实体也被迫接受这个接口。

在服务调用者角度,这样违法了接口隔离原则。而在服务提供者角度,这样违法了单一职责原则。

解决方案:这种情况就用接口隔离,把一个大接口分解成更小的接口。使每个小接口都描述一个单一的功能。也就是把本质不同的接口隔离开。

示例:

以下有两段代码:

        前段代码会体现违反接口隔离原则,导致接口中多余的方法被调用

        后段代码会体现使用接口隔离原则,让接口中本质不同的功能,单独成为一个接口                                                                                        

这段代码是京都某公子爷,开着自己的法拉利Car,撞车后又想开动它的坦克。

using System;
namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var driver=new Driver(new Car());
            driver.Drive();
        }
    }
    class Driver {
        private IVehicle _vehicle;
        public Driver(IVehicle vehicle11) { 
             _vehicle = vehicle11;
        }
        public void Drive() { 
            _vehicle.Run();
        }
    }
    interface IVehicle
    {
        void Run();
    }
    class Car : IVehicle
    {
        public void Run()
        {
            Console.WriteLine("开动了小汽车");
        }
    }
    class Truck : IVehicle
    {
        public void Run()
        {
            Console.WriteLine("开动了小卡车");
        }
    }
    interface ITank {
        void Run();
        void Fire();
    }
    class LightTank : ITank
    {
        public void Fire()
        {
            Console.WriteLine("轻型坦克开火");
        }

        public void Run()
        {
            Console.WriteLine("轻型坦克启动");
        }
    }
    class MediumTank : ITank
    {
        public void Fire()
        {
            Console.WriteLine("中型坦克开火");
        }

        public void Run()
        {
            Console.WriteLine("中型坦克启动");
        }
    }
    class HeavyTank : ITank
    {
        public void Fire()
        {
            Console.WriteLine("重型坦克开火");
        }

        public void Run()
        {
            Console.WriteLine("重型坦克启动");
        }
    }
}

//公子爷想开坦克的话,就将Driver类中字段设为ITank,传入ITank子类
//传入坦克实例,调用坦克启动方法

Driver类只是想开动车,那么传入胖接口ITank中的Frie方法实际上用不到。违背了接口隔离原则。

解决方法:将胖接口ITank分成两个接口(也就是让它继承两个接口):

此时对于实现ITank接口的类LightTank,传入Driver类中,由于Driver类只要用Run方法,那么ITank继承的IWeapon接口不会被传入调用。

using System;
namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var driver=new Driver(new LightTank());
            driver.Drive();
        }
    }
    class Driver {
        private IVehicle _vehicle;
        public Driver(IVehicle vehicle11) { 
             _vehicle = vehicle11;
        }
        public void Drive() { 
            _vehicle.Run();
        }
    }
    interface IVehicle
    {
        void Run();
    }
    class Car : IVehicle
    {
        public void Run()
        {
            Console.WriteLine("开动了小汽车");
        }
    }
    class Truck : IVehicle
    {
        public void Run()
        {
            Console.WriteLine("开动了小卡车");
        }
    }
    interface IWeapon
    {
        void Fire();
    }
    interface ITank: IVehicle,IWeapon{
    }
    class LightTank : ITank
    {
        public void Fire()
        {
            Console.WriteLine("轻型坦克开火");
        }

        public void Run()
        {
            Console.WriteLine("轻型坦克启动");
        }
    }
    class MediumTank : ITank
    {
        public void Fire()
        {
            Console.WriteLine("中型坦克开火");
        }

        public void Run()
        {
            Console.WriteLine("中型坦克启动");
        }
    }
    class HeavyTank : ITank
    {
        public void Fire()
        {
            Console.WriteLine("重型坦克开火");
        }

        public void Run()
        {
            Console.WriteLine("重型坦克启动");
        }
    }
}

情况二

2、传给调用者的接口是由几个小接口合并的,本来是要传入其中的小接口的,而现在传入的是合并小接口的大接口。那么就会将合格的服务者挡在门外,也就是不能调用单独实现该小接口的类。

示例

由前面第二段代码说明:如果Driver类传入的接口是ITank,那么实例Driver时,只能传入那3种坦克。不能传入Car类、Truck类。

但Driver类是需要所有的车都能开的,应该传入小接口IVehicle,而现在传入了合并的大接口ITank,就会将合格的服务者Car、Truck类挡在门外。

接口隔离原则(Interface Segregation Principle,ISP)是一个面向对象设计的原则,它主张应该把客户端对一个类的需求分解成更小、更具体的接口,而不是提供一个包含所有功能的大接口。这样做可以降低类之间的耦合度,使得每个接口只专注于完成特定任务,使得接口更易于维护和复用。

反射


反射(Reflection:)是编程语言提供的一种机制,允许程序在运行时检查和操作自身的结构(如类、方法、属性等),动态地获取和修改程序的状态。以不变应万变。

反射功能示例:

反射原理及依赖注入

展示未封装的反射用法,了解即可:

核心代码:

static void Main(string[] args)
{
    ITank tank=new HeavyTank();//静态类型

    //-------------以下都不是静态生成--不用new---------
    var t = tank.GetType(); //在内存中获得静态tank在运行时的动态信息,类
    object o=Activator.CreateInstance(t);//用t类型构造出object对象,并不知道o里面是什么
    MethodInfo fireMi = t.GetMethod("Fire");//反射出方法
    MethodInfo runMi = t.GetMethod("Run");
    fireMi.Invoke(o, null);
    runMi.Invoke(o, null);
}

完整代码:

using System;
using System.Reflection;
namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            ITank tank=new HeavyTank();//静态类型

            //-------------以下都不是静态生成--不用new---------
            var t = tank.GetType(); //在内存中获得静态tank在运行时的动态信息,类
            object o=Activator.CreateInstance(t);//用t类型构造出object对象,并不知道o里面是什么
            MethodInfo fireMi = t.GetMethod("Fire");//反射出方法
            MethodInfo runMi = t.GetMethod("Run");
            fireMi.Invoke(o, null);
            runMi.Invoke(o, null);
        }
    }
    class Driver {
        private IVehicle _vehicle;
        public Driver(IVehicle vehicle11) { 
             _vehicle = vehicle11;
        }
        public void Drive() { 
            _vehicle.Run();
        }
    }
    interface IVehicle
    {
        void Run();
    }
    class Car : IVehicle
    {
        public void Run()
        {
            Console.WriteLine("开动了小汽车");
        }
    }
    class Truck : IVehicle
    {
        public void Run()
        {
            Console.WriteLine("开动了小卡车");
        }
    }
    interface IWeapon
    {
        void Fire();
    }
    interface ITank: IVehicle,IWeapon{
    }
    class LightTank : ITank
    {
        public void Fire()
        {
            Console.WriteLine("轻型坦克开火");
        }

        public void Run()
        {
            Console.WriteLine("轻型坦克启动");
        }
    }
    class MediumTank : ITank
    {
        public void Fire()
        {
            Console.WriteLine("中型坦克开火");
        }

        public void Run()
        {
            Console.WriteLine("中型坦克启动");
        }
    }
    class HeavyTank : ITank
    {
        public void Fire()
        {
            Console.WriteLine("重型坦克开火");
        }

        public void Run()
        {
            Console.WriteLine("重型坦克启动");
        }
    }
}

展示依赖注入

依赖反转(DI)是个概念,依赖注入(DI)是以它为基础,结合接口、反射,的一个应用。

依赖注入需要依赖注入框架:

右击项目名,点击管理NuGet程序包,下载应用图中第二个:

依赖注入优点1:

就算有无数行有关HeavyTank代码,需要将HeavyTank改成MediumTank,只需改 sc.AddScope中的HeavyTank。常规写的,是没这么方便的。

        static void Main(string[] args)
        {
           var sc=new ServiceCollection();//依赖注入中最重要的就是这个容器
            
            //往容器中装一对类型,参数是接口,实现接口的类,typeof()是获取动态描述
            sc.AddScoped(typeof(ITank),typeof(HeavyTank));
            var sp=sc.BuildServiceProvider();
//----------------以上是程序之前注册,下面是任何地方都可以-----------------
            ITank tank=sp.GetService<ITank>();
            //这里就算有无数行有关HeavyTank代码,需要将HeavyTank改成MediumTank,只需改 sc.AddScope中的HeavyTank
            tank.Fire();
            tank.Run();
        }
    }

依赖注入优点2:在动态new一个Driver类型时,会自动在容器里面将需要的IVehicle类型注入

        static void Main(string[] args)
        {
           var sc=new ServiceCollection();//依赖注入中最重要的就是这个容器
            
            //往容器中装一对类型,参数是接口,实现接口的类,typeof()是获取动态描述
            sc.AddScoped(typeof(ITank),typeof(HeavyTank));

            sc.AddScoped(typeof(IVehicle),typeof(Car));
            sc.AddScoped<Driver>();

            var sp=sc.BuildServiceProvider();
//----------------以上是程序之前注册,下面是任何地方都可以-----------------
            var driver=sp.GetService<Driver>();//它在动态new一个Driver类型时,会自动在容器里面将需要的IVehicle类型注入
            driver.Drive();
        }

用反射实现更松的耦合

常用于插件程序

using System.Reflection;

public static T ExecuteAction<T>(object targetObject, string methodName, params object[] args)
{
    // 获取目标对象的类型信息
    Type targetType = typeof(T);

    // 使用反射获取指定方法
    MethodInfo methodInfo = targetType.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance);

    if (methodInfo != null)
    {
        // 创建委托并调用方法
        Delegate del = methodInfo.CreateDelegate(typeof(Delegate), targetObject);
        return (T)del.DynamicInvoke(args);
    }
    else
    {
        throw new ArgumentException($"Method {methodName} not found in type {typeof(T).FullName}");
    }
}

// 使用示例
class MyClass
{
    public void MyMethod(string param) => Console.WriteLine($"MyClass: {param}");
}

var myInstance = new MyClass();
ExecuteAction<MyClass>(myInstance, "MyMethod", "Hello from reflection");

在这个例子中,ExecuteAction函数可以根据传入的类型和方法名,在运行时找到并执行相应的方法,这使得调用者无需关心具体的实现细节,提高了代码的灵活性和解耦。

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

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

相关文章

MT8768/MTK8768安卓核心板性能参数_联发科安卓智能模块开发方案

MT8768安卓核心板 是一款采用台积电12nm FinFET制程工艺的智能手机芯片。MT8768核心板不仅提供所有高级功能和出色体验&#xff0c;同时确保智能终端具备长电池寿命。该芯片提供了一个1600x720高清(20:9比例)分辨率显示屏&#xff0c;排除了清晰度和功耗之间的平衡问题。该芯片…

VBA技术资料MF229:以毫米为单位设置行高和列宽

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

深入JMeter核心引擎:揭秘JmeterEngine、StandardJmeterEngine、ClientJmeterEngine与Remote的奥秘

引言 Apache JMeter是一款广泛使用的开源性能测试工具&#xff0c;它能够帮助开发者和测试人员模拟大量并发用户对应用程序进行负载测试。JMeter的强大功能和灵活性源于其精心设计的核心引擎。本文将深入探讨JMeter的核心引擎&#xff0c;包括JmeterEngine、StandardJmeterEng…

软件工程导论 选填题知识点总结

一 原型化方法是一种动态定义需求的方法&#xff0c;提供完整定义的需求不是原型化方法的特征&#xff0c;其特征包括尽快建立初步需求、简化项目管理以及加强用户参与和决策。 软件危机的表现包括用户对已完成的软件系统不满意的现象经常发生、软件产品的质量往往靠不住、软件…

Rust中Tracing 应用指南

欢迎来到这篇全面的Rust跟踪入门指南。Rust 的tracing是一个用于应用程序级别的诊断和调试的库。它提供了一种结构化的、异步感知的方式来记录日志和跟踪事件。与传统的日志记录相比&#xff0c;tracing能够更好地处理复杂的异步系统和分布式系统中的事件跟踪&#xff0c;帮助开…

机器学习实战:银行客户是否认购定期存款

项目结构与步骤 1. 项目概述 项目名称&#xff1a;葡萄牙银行电话营销活动分析与定期存款认购预测目标&#xff1a;通过分析银行的电话营销数据&#xff0c;构建模型预测客户是否会认购定期存款。数据来源&#xff1a;葡萄牙银行营销活动数据集关键挑战&#xff1a;数据不平衡…

服务器数据恢复—raid5阵列热备盘上线失败导致EXT3文件系统不可用的数据恢复案例

服务器数据恢复环境&#xff1a; 两组分别由4块SAS硬盘组建的raid5阵列&#xff0c;两组阵列划分的LUN组成LVM架构&#xff0c;格式化为EXT3文件系统。 服务器故障&#xff1a; 一组raid5阵列中的一块硬盘离线。热备盘自动上线替换离线硬盘&#xff0c;但在热备盘上线同步数据…

C++vector

Cvector是标准库中的一员&#xff0c;vector直译过来是“向量”、“矢量”的意思&#xff0c;在C中&#xff0c;是一个动态的数组容器&#xff0c;可以动态的开辟空间&#xff0c;自动实现内存的管理&#xff0c;不需要我们手动操作&#xff0c;在标准库中&#xff0c;写作一个…

“漫步北京”小程序及“气象景观数字化服务平台”上线啦

随着科技的飞速发展&#xff0c;智慧旅游已成为现代旅游业的重要趋势。近日&#xff0c;北京万云科技有限公司联合北京市气象服务中心&#xff0c;打造的“气象景观数字化服务平台“和“漫步北京“小程序已经上线&#xff0c;作为智慧旅游的典型代表&#xff0c;以其丰富的功能…

LlamaIndex+本地部署InternLM实践

LlamaIndex本地部署InternLM实践 XTuner是一个调整模型参数的小工具,通过对于给定的大模型输入有限的参数来调整同类型问题的结果输出 ‌LlamaIndex‌是一个将大语言模型&#xff08;LLMs&#xff09;和外部数据连接在一起的工具&#xff0c;主要用于增强大模型的知识获取能力…

【阵列信号处理】相干信号和非相干信号生成

文章目录 一、总结二、知识点相干&#xff08;coherent&#xff09;和非相干&#xff08;incoherent&#xff09;信号相干信号生成代码 相关信号&#xff08;correlated signal&#xff09;相关信号生成代码 正交信号定义 本文记录博主的科研日记。如果对博主的其他文章感兴趣&…

vue3项目部署在阿里云轻量应用服务器上

文章目录 概要整体部署流程技术细节小结 概要 vue3前端项目部署在阿里云轻量服务器 整体部署流程 首先有一个Vue3前端项目和阿里云应用服务器 确保环境准备 如果是新的服务器&#xff0c;在服务器内运行以下命令更新软件包 sudo apt update && sudo apt upgrade -y …

东土科技孵化的“网联汽车高速通信技术”前沿产品亮相2024WICV大会

2024世界智能网联汽车大会&#xff08;WICV&#xff09;于近日在北京召开。本次大会发布了由中国汽车工程学会组织全球200余位专家&#xff0c;联合评审遴选出未来十年对于智能网联汽车发展具有重要影响的十大技术趋势&#xff0c;包括“面向高级别自动驾驶的超级人工智能”“网…

【云计算网络安全】解析 Amazon 安全服务:构建纵深防御设计最佳实践

文章目录 一、前言二、什么是“纵深安全防御”&#xff1f;三、为什么有必要采用纵深安全防御策略&#xff1f;四、以亚马逊云科技为案例了解纵深安全防御策略设计4.1 原始设计缺少安全策略4.2 外界围栏构建安全边界4.3 访问层安全设计4.4 实例层安全设计4.5 数据层安全设计4.6…

关于相机选型的一些参数说明

上一篇&#xff1a;关于相机的一些参数计算&#xff08;靶面、视野等&#xff09; 目录 1.卷帘快门和全局快门1.1 卷帘快门1.2 全局快门PS&#xff1a;视觉伺服与快门选择 2.黑白和彩色3.CCD和CMOS3.1 CCD3.2 CMOSCCD VS CMOS 4.面阵和线扫4.1 面阵4.2 线扫4.3 面阵 VS 线扫 5.…

C 语言复习总结记录二

C 语言复习总结记录二 一 控制语句 1、语句的分类 表达式语句函数调用语句复合语句控制语句空语句 控制语句 控制程序的执行流程&#xff0c;实现程序的各种结构方式 C 语言支持三种结构 &#xff1a;顺序结构、选择结构、循环结构&#xff0c;由特定的语句定义符组成C语言…

【mongodb】社区版8:改变配置bindip和授权

更改配置 sudo systemctl restart mongod (base) root@k8s-master-pfsrv:/home/zhangbin# sudo tail -n 20 /var/log/mongodb/mongod.log 日志感觉是成功了:{"t":{"$date":"2024-11-19T19:57:47.076+08:00"

28.UE5游戏框架,事件分发器,蓝图接口

3-3 虚幻游戏框架拆解&#xff0c;游戏规则基础_哔哩哔哩_bilibili 目录 1.游戏架构 2.事件分发器 2.1UI控件中的事件分发器 2.2Actor蓝图中的事件分发器 2.2.1动态决定Actor的分发事件 2.2.2父类中定义事件分发器&#xff0c;子类实现事件分发器 2.3组件蓝图中实现事件…

P1 练习卷(C++4道题)

1.纷繁世界 内存限制&#xff1a;256MB 时间限制&#xff1a;1s 问题描述 这是一个纷繁复杂的世界。 某一天清晨你起床很迟&#xff0c;没有吃上早饭。于是你骑着自行车去超市&#xff0c;但是你又发现商店的工作人员已经重新贴上了价格标签&#xff0c;零食价格都涨了50%。你…

挂壁式空气净化器哪个品牌的质量好?排名top3优秀产品测评分析

随着挂壁式空气净化器市场的不断扩大&#xff0c;各类品牌与型号琳琅满目。但遗憾的是&#xff0c;一些跨界网红品牌过于追求短期效益&#xff0c;导致产品在净化效果与去除异味方面表现平平&#xff0c;使用体验不佳&#xff0c;甚至可能带来二次污染风险&#xff0c;影响人体…