[…]耦合(或依赖性)是每个程序模块依赖于其他模块中每个模块的程度。


—维基百科
http://en.wikipedia.org/wiki/Coupling_(computer_science)


在面向对象的编程中,删除依赖关系是通过使用接口来完成的。 因此,如果类A依赖于类B,我们将引入接口C,该接口C由B实现。现在A依赖于C(请参见下文)。



java interface 解耦 java中的解耦是什么意思_java interface 解耦



解耦的第一步称为通过接口编程 。 无论如何,我们仍然必须通过C接口“馈送”类A,无论它是B对象还是实现C的任何实例。因此,我们需要一个此类的实例。 在标准代码中,类A以这种方式实例化B:



publicclassA{
    privateCc=newB();
}


噢亲爱的! 看来我们又从A到B引入了依赖关系...希望这个问题有答案,即依赖关系注入 。 在依赖关系注入中,外部模块负责实例化和设置类B的对象。代码变为以下代码:


publicclassA{

    privateCc;

    publicvoidsetC(Cc){
        this.c=c;
    }
}



DI框架创建一个新的B并将其通过setter传递给A对象:它是唯一了解B类(并因此而依赖于它)的组件。尽管如今,DI显然已经成为主流,但很大程度上要归功于Spring框架 ,其他解决方案,以消除依赖性。 一种这样的解决方案是Service Locator核心JEE模式:



java interface 解耦 java中的解耦是什么意思_spring_02



在此图中,客户端不直接引用目标,而是通过称为服务定位符的中间对象获取目标。 以下代码说明了此模式,该代码执行JNDI查找:



publicclassServiceLocator{

    /** Singleton. */
    privatestaticServiceLocatorme;

    /** JNDI context to connect to. */
    privatefinalInitialContextcontext;

    /** Objects cache. */
    privateMapcache;

    /**
     * Gets an instance of the locator.
     *
     * @return Singleton
     * @throws NamingException
     */
    publicstaticServiceLocatorgetInstance()throwsNamingException{
        if(me==null){
            me=newServiceLocator();
        }
        returnme;
    }

    privateServiceLocator()throwsNamingException{
        context=newInitialContext();
    }

    /**
     * Get the object stored under the name in the JNDI tree. First look up in
     * the cache, then in the backing tree.
     *
     * @param name
     * @return Object stored
     * @throws NamingException
     */
    publicObjectlookup(Stringname)throwsNamingException{
        Objectobject=cache.get(name);
        if(object==null){
            object=context.lookup(name);
            cache.put(name,object);
        }
        returnobject;
    }
}



显然,此定位器非常简单,并采用了最简单的缓存策略。 但是,它有效。



自Java 1.3以来,在JDK中就存在另一种形式的服务定位器(尚不为人所知)(阅读:只有真正的极客才知道),它是服务提供者 。 此功能可以节省生命。 如果您将JAR(接口(API)之一和实现之一)完全分开,它可以让您将客户端代码与实现完全脱钩,并仅使用接口。 怎么做?



首先,您必须将代码完全独立地分开接口和实现(请参见上文)。 然后,对于每个接口,在META-INF / services下的实现JAR中创建一个新文件。 文件名应为接口的标准名称,文件内容应为所选实现的标准名称。 最后,在您的代码中,您应该仅使用以下代码段:



java.util.ServiceLoader.load(MyFullyQualifiedInterfaceName.class);



就是这样,只要您注意将接口和实现JAR都放在类路径上即可。 不过要提一个警告:如果类路径上有多个实现,则无法确定选择。 现在,您可以通过这个简单而强大的技巧使同事惊讶。 如果您了解OSGI,那么您会发现它看起来很像OSGI服务层的雏形。 该解决方案的优点是您只需要JDK 1.3+。 缺点是您无法管理应用程序的生命周期,仅提供服务实现。