Java 单例提供者与常规提供者

Java 单例提供者与常规提供者,java,dependency-injection,singleton,provider,Java,Dependency Injection,Singleton,Provider,我正在尝试(第一次)使用依赖项注入构建令牌。我有一个菱形层次结构问题,我需要将我的数据的有符号散列预先添加到实际数据本身 因此,我发现自己多次调用原始数据提供程序上的get()。这很好,但在图的后面,还有基于时间的组件,因此,在后续调用中返回的数据是不同的 有人建议使用单例提供者模型。对于此提供程序,对get()的后续调用将返回相同的对象(引用)。此提供程序缓存第一次调用get()的结果,并持续返回该结果。在注入依赖项时,我将该提供程序的同一实例注入两次,结果它将两次返回相同的数据 这让我思考,

我正在尝试(第一次)使用依赖项注入构建令牌。我有一个菱形层次结构问题,我需要将我的数据的有符号散列预先添加到实际数据本身

因此,我发现自己多次调用原始数据提供程序上的get()。这很好,但在图的后面,还有基于时间的组件,因此,在后续调用中返回的数据是不同的

有人建议使用单例提供者模型。对于此提供程序,对get()的后续调用将返回相同的对象(引用)。此提供程序缓存第一次调用get()的结果,并持续返回该结果。在注入依赖项时,我将该提供程序的同一实例注入两次,结果它将两次返回相同的数据

这让我思考,是否有任何情况下你不想使用单例提供者?如果您希望得到不同的结果,那么不应该每次都创建一个新的提供者实例吗

public MyUnderscoreStringSingletonProvider implements Provider<String>
{
    private final Provider<String> mySomeOtherStringProvider;
    private String myCachedString;

    public MyUnderscoreStringSingletonProvider( 
        Provider<String> someOtherStringProvider )
    {
        mySomeOtherStringProvider = someOtherStringProvider;
        myCachedString = null;
    }

    @Override
    public String get()
    {
        if( myCachedString == null )
        {
            myCachedString = create();
        }
        return myCachedString;
    }

    private String create()
    {
        return "_" + mySomeOtherStringProvider.get();
    }
}

// ...

public class SomeCoolService
{
    // ...

    public Provider<String> injectStringDoubler()
    {
        final Provider<String> stringProvider = 
            injectUnderScoreStringProvider();
        return new TwoConcatendatedStringsProvider(
            stringProvider,
            stringProvider );
        // This would not work if Singleton Provider was not used.
        // Why should we ever use non-Singleton Providers?
    }

    protected Provider<String> injectUnderScoreStringProvider()
    {
        return new MyUnderscoreStringSingletonProvider(
            injectMyTimebasedStringProvider() // returns different result
                                              // depending
                                              // on time.
            );
    }

    // ...
}
public MyUnderlineStringSingletonProvider实现提供程序
{
私人最终提供者mySomeOtherStringProvider;
私有字符串myCachedString;
公共MyUnderlineStringSingleton提供程序(
提供者(其他提供者)
{
mySomeOtherStringProvider=someOtherStringProvider;
myCachedString=null;
}
@凌驾
公共字符串get()
{
如果(myCachedString==null)
{
myCachedString=create();
}
返回myCachedString;
}
私有字符串create()
{
返回“u”+mySomeOtherStringProvider.get();
}
}
// ...
公共类服务
{
// ...
公共提供程序injectStringDoubler()
{
最终提供程序字符串提供程序=
InjectOutlineStringProvider();
返回新的TwoConcatedStringsProvider(
stringProvider,
stringProvider);
//如果不使用单例提供程序,这将不起作用。
//我们为什么要使用非单例提供者?
}
受保护的提供程序InjectOutlineStringProvider()
{
返回新的MyUnderlineStringSingleTonProvider(
injectMyTimebasedStringProvider()//返回不同的结果
//取决于
//准时。
);
}
// ...
}

初始化对象有两种方法,一种是从头开始创建对象。另一种是将现有对象重置为其初始状态

最终,就像软件开发中的许多其他事情一样,它归结为对所涉及成本的估计

单例很容易实现,并且在大多数情况下提供了一个资源高效的解决方案, 但是,它们不能在非线程安全的条件下使用。e、 g.SimpleDataFormat作为单例将提供“随机”错误


在创建对象的成本明显高于重置对象的成本的情况下,对象池非常有用,然而,实现它们并不是件小事,因此,如果您没有现成的,并且没有迫切的理由实现它们,那么遵循正常的对象创建/销毁流程是更好的方法。

为什么您说Java中存在菱形层次结构问题?@SenJacob-这是依赖项注入图中的菱形问题。同一个对象需要使用两次,如果没有单例提供程序,它将是get()调用每次提供的不同对象。问题是,你为什么不使用单身汉?有没有这方面的例子可以提供?初始化对象有两种方法,一种是从头开始创建。另一种是将现有对象重置为其初始状态。如果创建对象的成本明显高于重置对象的成本,那么使用预创建的实例池是有意义的。@BevynQ-因此,不使用预创建的实例池的唯一优点是减少了内存占用?@studro-Singleton更容易实现,池不是微不足道的,作为最后的手段,我将只实现一个池。如果一个池已经存在并且很容易管理,那就太好了,否则如果我可以不创建和丢弃对象就可以了。