IOC容器逻辑上如何解耦

40 篇文章 1 订阅
13 篇文章 0 订阅

        初学SpringIOC容器,我们对于解耦可能还是处于一个相对抽象的概念理解,后面作者也是查找了一些资料,本片文章就用一个例子来说明IOC容器解耦的妙处

        假设现在公司需要完成一个与新闻公司的合作项目,项目需要与新闻社进行合作,获取新闻社的新闻并且存储到我们的数据库中,用于展示。

        我们可以分析一下:当有新的新闻时,通过我们设计的程序,定时的到指定的新闻服务器下,去抓取最新的新闻,然后将这些新闻在通过指定的程序存储到我们的数据库中。因此整个处理过程就分为两大块:1.抓取新闻2.存储新闻

        我们定义两个接口,用于规范两大业务功能,其中Listener接口用于处理抓取新闻的功能,Persistener用于处理存储新闻的功能。

public interface Listenener {
    Object getNews1();
    Object getNews2();
        ...
}
public interface Persistener {
    void saveNews1(Object news);
    void saveNews2(Object news);
        ...
}

        之后提供了一个Provider类去处理整个新闻的整体流程

public class Provider {
    private Listenener listenener;
    private Persistener persistener;

    public void handleNews(){
        Object news1 = listenener.getNews1();
        Object news2 = listenener.getNews2();
                ...
        persistener.saveNews1(news1);
        persistener.saveNews2(news2);
                ...
    }
}

        到此我们已经可以感受到整个流程了,我们看Provider可以发现,代码可以实现正常的运行逻辑,但是两个属性都是null,而两者又是接口,无法new出对象,所以需要实现类去注入对象。

        此时有一家新闻社A宣布与我们合作,我们派员工针对与他们的新闻服务器数据设计了AListener和APersistener两个实现类,分别用于抓取A新闻社的时事新闻,和将抓取的内容存储到数据库两个具体功能。

        如果不使用IOC容器,那么一般情况下我们就会直接在Provider的handleNews方法中直接new出两个实现类对象。

import ...AListenener;
import ...Apersistener;

public class Provider {
    private Listenener listenener;
    private Persistener persistener;

    public void handleNews(){
        listenener = new AListenener();
        persistener = new Apersistener();
        Object news1 = listenener.getNews1();
        Object news2 = listenener.getNews2();
                ...
        persistener.saveNews1(news1);
        persistener.saveNews2(news2);
                ...        
    }
}

        如上,Provider类无意间就引入了两个包,Provider与AListener还有APersistener的耦合性上升了,这三个类开始绑定在一起。

        此时,无论我们在何时何地创建Provider对象,调用方法时都将在Provider类导入AListener和APersistener类的包,创建对应的对象。(这里留个问题1,在文章末尾解答,读完文章后再回来看此处的问题

        如此运行是完全没有逻辑上的问题,但是这时,B新闻社决定与我们合作,公司派员工写了用于从B新闻服务器抓取时事新闻的BListener实现类。当公司打算派人实现接口Persistener时,领导顿住了。咦,我这不是还有一个专门存储数据用的APersistener类吗?那还浪费钱去重新做一个干什么。(由于抓取新闻的功能都由Listener接口去约束,所以无论实现类如何书写,返回值都是一样的,对于一样处理好的数据,同一个Persistener就可以处理)。那么领导就开始思考,既然APersistener能用,那我干脆就还是用Provider处理与B社的合作吧。

        现在问题来了,Provider已经与AListener绑定在一块了,项目已经投入使用了,现在再去修改源码,也免不了成本,假设你有时间,不怕麻烦终于修改了源码,这时候突然又来了一家新闻社C,那咱们继续花时间修改源码吗?现在我们只与一家A合作,当我们与十家合作时,再去修改源码就相当的麻烦, 时间就是小钱钱。有没有一种方法,不是我们手动修改源码主动的给Provider提供属性,而是当Provider需要AListener时就提供给他AListener对象,需要BListener时就提供给他BListener对象呢?

        这时IOC容器默默的举起了手,通过IOC容器读取配置文件的方法,我们只需要将AListener,BListener对象提前创建好,存放到一个容器中,当创建Provider对象时看需要哪个,那就拿走哪个。

        我们在很多地方可能都需要导入一些包,去完成对象的创建,依赖分散在各处,那么耦合就分散在各处,最后可能整个项目牵一发而动全身。一处没完成,处处等。一处报错,处处有罪。项目流程的进行与中间的测试变得异常困难。正如一句话:原子弹下无冤魂。当我们使用IOC容器使控制权反转后,联系就不会在一件事的不同时间点出现,出现一件解决一件,而是从一开始就把解决问题的答案放在搜题软件里,需要哪个搜哪个,没有哪个配置哪个,然后提供哪个。

问题1:这时可能就要有人来问了,那为什么非要在方法中给两个属性赋值呢,我们在创建Provider对象时干脆直接用set方法赋值,或者含参构造器给这两个属性赋值,Provider不就不用导入两个包了吗?这样Provider与这两个类的耦合性不就降低了吗?

        这样想确实没有问题,Provider与这两个类的耦合性确实降低了。我们在获取Provider对象时就直接给参数赋值,那么Provider类中就完全不需要导入AListener或者BListener的包了,这么一想,我们的IOC容器好像还是多余的设计,我们只需要在获取Provider对象时根据需要给属性赋值,那不就行了吗?

Provider provider = new Provider(new AListenener(),new APersistener());
Provider provider = new Provider(new BListenener(),new APersistener());

        这么想就大错特错了,我们最终处理问题时,需要创建Provider对象,调用Provider中的方法,那么我们处理问题的类就不需要导入AListenener的包,或者导入BListenener的包了吗?当然不可能。我们回到最初,我们为什么需要Provider对象,就是因为Provider对象能解决问题。无论我们用哪个类最终处理转移新闻这个目的,我们都需要自己手动在代码中创建对象,无论对象拖到哪创建,都最终有一个地方需要我们手动创建对象。一旦创建对象那么就需要导入相关包,创建联系,而联系一旦在类与类之间存在,就不方便修改。所以我们需要一个人,去处理联系,这个人就是IOC。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Aristocrat l

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值