女朋友强依赖我!我引入IOC后,从此我们的关系微妙而稳固!

此文从面向对象设计角度分析依赖倒置原则,引入依赖注入,IOC相关内容进行探讨,文中引用女朋友案例可能引起分手风险,故理解为 new 对象。

想起在学校的时候,有一个任务就是设计一款宠物商店项目。那时候引入三层架构设计概念,分为UI(表现层)、BLL(业务逻辑层),DAL(数据访问层)。

▲图/ 简单三层架构示例

每一层各司其职,表现层只管负责用户的界面交互;业务逻辑层只管计算、验证,业务规则等等;数据访问层则负责与数据库的增、删、改,查。

设计完交差后,就会思考,为啥要使用这个,能给我带来什么好处。学完面向对象设计思想之后得出了答案,当时判定程序的良好基本可以通过“高内聚,低耦合”的方式。

确实,三层架构设计能够符合程序的高内聚,达到解耦的目的,但是并没有达到低耦合的层级,自上而下层层依赖,其耦合性还是相对较高。或许当时设计的项目相对较简单,没有直接体现出来。

工作之后才发现,三层架构设计的应用还是相对较广,曾经就有一些项目运用三层架构之后,不断的需求变更导致一层的改动,都会造成联级改动。

如果要解决这个问题,面向对象设计中有一个设计原则,就是依赖倒置原则(DIP)。

高层模块不应该依赖低层模块,两者都应依赖于抽象层。

抽象层不应该依赖于实现,实现应该依赖于抽象。

模块间的依赖通过抽象发生的,实现类之间不发生直接的依赖关系,依赖关系是通过接口或者抽象类产生的。

这个原则听起来很像是“针对接口编程,不针对实现编程”,的确很相似,然而这里更强调“抽象”。这里就是要求设计者们编程时需要有一定的抽象思维啦。

依赖倒置的原则,也可以让三层架构升级,具有抽象化。

▲图/ 升级抽象化三层架构示例

当然DIP的主要目的并不是这,目的就是为了让系统架构更加的稳定、更加灵活,更好的应对需求的变化。

无论多少种设计模式或者多少种设计原则,主要就是让系统稳定,能够应付需求的千变万化,并不是花里胡哨的存在。毕竟,相对于细节的多变性,抽象化会更加稳定。

那么程序中要使用依赖倒置原则,一个呼声最高的名词就是控制反转(Inversion of Control),简称IOC。

IOC的存在可以说是更好的实现依赖倒置原则,也让程序更加的灵活和稳固。

至于怎么理解这个IOC呢,可以请出女朋友的例子来说明。

女朋友饿了,想要吃这吃那,对食物有需求。

此时会怎么做呢?

1.自己去找吃的,去冰柜或者厨房去拿吃的。

2.找男朋友,向你撒娇,给她递食物。

第一种,女朋友可能不太聪明,也不会做饭,拿到的食品没有加工,或者没有清洗就直接吃,会存在一定的风险。

第二种,向男朋友撒娇,表达需求。此时你可能会表现出男友力Max,会去冰柜里拿出食物并洗干净给她,或者进厨房做饭给她吃,甚至还可以喂她。

啊?你要上班或者出差不在家?此时你女朋友发现隔壁邻居老王很富有且很会做饭,便向隔壁老王打电话撒娇表达需求,此时隔壁老王会做一手拿手好菜端到你女友面前并喂她。

我们可以看到,你的女朋友从对食物的需求,从主动去冰柜或者厨房(正转)获取食物,到想要吃食物而被动(你或者老王)获得(反转)食物。

女朋友对食物的需求,食物的控制权转移到了你或者老王的手上。

编程时,相当于组件对象控制权的转移。

例如,方法A中需要使用方法B,方法B需要使用方法C,此时方法B和方法C并不由自己本身来负责,而是由第三方来创建!

这个过程,称为控制反转,最直观的体现就是依赖注入(DI),反转依赖。

上述例子,女朋友想要的是食物(依赖,对食物的依赖),食物由第三方的你(男朋友)或者老王来负责,做好之后拿给(注入)你女朋友。

控制反转的是一种结果,一种由依赖食物到注入给定目标的结果。正是因为有了依赖注入,才需要控制反转,控制依赖的对象的选择权反转到目标结果。

如果明白了以上的内容,就能明白依赖注入和控制反转的目的。

为什么要依赖注入?因为要实现控制反转

为什么要控制反转?因为软件设计体系中需要符合依赖倒置原则

说到IOC(控制反转),我们会听到IOC容器的概念,IOC和IOC容器也有本质的区别。

IOC,定义就是一种反转流、依赖和接口的方式,它把传统上由程序代码直接操控的对象的调用权交给第三方(容器),通过第三方来实现对象组件的装配和管理。

所谓的IOC容器,可以理解为一个对象,通常是由依赖注入框架来提供的。负责映射依赖、管理对象的创建和生命周期。

说到IOC对象,我想大家应该有一个概念,就是对象池的概念。IOC容器可以理解为一个对象池的概念。

例如耳熟能详的数据库连接池,线程池等都是对象池的概念。

所谓的对象池,就是对象的容器,通过在一个容器中池化(实例化,也就是new)对象,并根据需要重复使用这些池化对象来满足性能上的需求。

当一个对象被激活时,便从池子里取出。用完时,又放回池中,等待下一个请求。一般用于对象的初始化过程代价较大或者使用频率较高的场景。

通俗讲,就是多个对象的实例化,资源释放都是交给对象池来处理。

依赖注入框架,目前使用较多的有 Unity、Autofac、Ninject等。

相关的框架也可以通过搜集文档进行了解,此处以Unity框架作为例子来实现。

▲图/ 抽象化鸟类示例

 //鸟类接口
 public interface IBird
    {
        public string Eat();
    }
    public class Cuckoo : IBird
    {
        public string Eat()
        {
            return "布谷鸟正在吃东西...";
        }
    }
    public class Sparrow : IBird
    {
        public string Eat()
        {
            return "麻雀鸟正在吃东西...";
        }
    }
    //鸟类工厂
    public static IBird GetEat(string birdType)
        {
            if (string.IsNullOrEmpty(birdType))
            {
                return null;//这里可以使用空对象模式
            }
            switch (birdType)
            {
                case "Cuckoo": return new Cuckoo();
                case "Sparrow": return new Sparrow();
                default:
                    return null;
            }
        }
    //工厂方法调用 
    public class BirdSample
    {
        public IBird _bird { get; set; }
        public BirdSample(string birdType)
        {
            _bird = BirdFactory.GetEat(birdType);
        }
        public void Eat()
        {
            Console.WriteLine($"小鸟们开始,吃东西了");
            Console.WriteLine(_bird.Eat());
        }
    }
       
    }
 //普通调用方法,由工厂实例对象
 public static void Main(string[] args)
        {
            BirdSample birdSample = new BirdSample("Cuckoo");
            birdSample.Eat();
        }
 //使用Unity容器化
 public static void Main(string[] args)
        {
            var container = new UnityContainer();
            //此处通过反射的方式实现,通过扫描程序集,找到相应的类进行主从到容器
            //注册类型可以更改,也可以通过配置文件,动态加载
            container.RegisterType<IBird, Cuckoo>();
            container.RegisterType<BirdSample>();
            var bird = container.Resolve<BirdSample>();
            bird.Eat();
        }

以上内容,就是依赖倒置原则,IOC的内容了。

希望能够帮助到伙伴们,文中示例有可能引发分手风险,在此希望多加支持点个赞!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值