打破 Dagger 中的循环依赖

Posted

技术标签:

【中文标题】打破 Dagger 中的循环依赖【英文标题】:Breaking cyclic dependency in Dagger 【发布时间】:2015-10-13 03:23:03 【问题描述】:

我对 dagger 很陌生——我什至不知道它是否适用于我的应用程序

我有一个搜索页面,它返回有关给定名人的最新消息。

我编写了一个测试来验证当我们搜索一个受欢迎的名人时结果是否会显示在页面上。

page 有一个searchField,它的构造函数中需要page,因此我用于测试的网络驱动程序可以选择它。

名人搜索页面测试

public class CelebritySearchPageTest 
    @Test
    public void testSearchResultsForKevinBaconVerifyHisPopularity() 
        CelebritySearchPage searchPage = new CelebritySearchPage();
        searchPage.searchFor("Kevin Bacon");
        Assert.assertTrue(searchPage.getNumberOfResults() > 9999999, "Verify that Kevin Bacon is still relevant");
    

名人搜索页面

public class CelebritySearchPage extends Page 
    @Inject
    @Named("search field")
    TextField searchField;

    public void searchFor(String text) 
        searchField.setText(text);
        // ...
    

    public int getNumberOfResults() 
        // ...
    

名人搜索页面模块

@Module(injects = CelebritySearchPage.class)
public class CelebritySearchPageModule 
    @Provides
    @Named("search field")
    public TextField provideSearchField() 
        return new TextField(/* How do I get the page? */, "#searchField");
    

页面

public abstract class Page 
    // ...

文本字段

public class TextField 
    protected Page page;
    protected String selector;

    public TextField(Page page, String selector) 
        this.page = page;
        this.selector = selector;
    

    public void setText(String text) 
        // ...
    

问题是page 需要searchField,但searchField 需要page。如何克服这种循环依赖?

我无法在 CelebritySearchPage 中初始化 searchField

【问题讨论】:

为什么TextField需要Page? @AndreasFrische textField.getFullSelector() 致电page.getFullSelector() 好的。也许然后注入一个 FullSelectorHolder 。或使用 Lazy:“有时您需要延迟实例化对象。对于任何绑定 T,您可以创建一个延迟实例化的延迟实例化,直到第一次调用 Lazy 的 get() 方法。”跨度> @AndreasFrische 您能否添加一个答案,说明您将如何使用 Lazy 方法?听起来很有希望。如果可行,我会接受。 【参考方案1】:

考虑一下:

名人搜索页面

public class CelebritySearchPage extends Page 
    private final Lazy<TextField> searchField;
// always prefer constructor injection
// avoid @Named if possible, since the compiler cannot check the string
    @Inject
    CelebritySearchPage(@Named("search field") Lazy<TextField> searchField) 
        this.searchField = searchField; 
    

文本字段

public class TextField 
    protected final Lazy<Page> page;
    protected final String selector;

    @Inject TextField(Lazy<Page> page, String selector) 
        this.page = page;
        this.selector = selector;
    

/*
Lazy::get()
Return the underlying value, computing the value if necessary. All calls to      the same Lazy instance will return the same result.
*/

我想一个 Lazy 也应该足够了。

【讨论】:

我该如何构造CelebritySearchPage,因为TextFieldCelebritySearchPage 在它们的构造函数中需要彼此。 不要构造。注入。 如何注射?你能展示一个使用页面而不构建它的例子吗? 说实话,阅读精美的手册。从这里开始:github.com/google/guice/wiki/Motivation github.com/google/guice/wiki/…

以上是关于打破 Dagger 中的循环依赖的主要内容,如果未能解决你的问题,请参考以下文章

我收到“循环依赖”Android Dagger Hilt 错误

golang中包循环依赖问题

压缩 Django 迁移时的循环依赖

汇编效率优化:打破依赖链

Dagger2 和依赖组件中的限定符

spring中的循环依赖