我是Generics的新手,也是Java中的Singleton模式。我有以下问题:
Generic类是否与Singleton Pattern兼容,即具有静态实例?
如果是这样,我有以下要转换为Singleton的Generic类。什么是最佳做法?
(初学者问题)有没有一种很好的方法可以在运行时取消生成类的实例?将类作为参数传递给getInstance()?
class GenFooSingleton <T>
{
private T t;
// Prevent direct instantiation
private GenFooSingleton(T o){
this.t = o;
}
private static GenFooSingleton INSTANCE = null;
// Returns the single instance of this class, creating it if necessary
static synchronized <T> GenFooSingleton<T> getInstance(T tClass)
{
if (INSTANCE == null)
{
INSTANCE = new GenFooSingleton<>(tClass);
}
return INSTANCE;
}
}
我使用Generic with Singleton的用例:
1。为何选择Generic? 首先,让我说我有一个以下类型的数据开头的以下Singleton存储库,以下示例来自我在googlesamples/android-architecture
中学到的内容class FooRepository implements FooDatasource
{
private final FooDatasource local;
private final FooDatasource remote;
Map<String, Foo> mCahcedItems;
// Prevent direct instantiation
private FooRepository(FooDatasource remote, FooDatasource local){
this.remote = remote;
this.local = local;
}
private static FooRepository INSTANCE = null;
// Returns the single instance of this class, creating it if necessary
public static synchronized FooRepository getInstance(FooDatasource remote, FooDatasource local)
{
if (INSTANCE == null)
{
new FooRepository(remote,local);
}
return INSTANCE;
}
// implement CRUD methods
@Override
public Flowable<List<Foo>> getFoos(){
// Update the mCahcedItems with the list of Foos
// return a list of Foos and syncing between the local and remote datasources...For brevity the bunch of Rxjava implementation is omitted.
}
@Override
public Flowable<Optional<Foo>> getFoo(){
// Update the mCahcedItems with Foo
//...
}
}
但我可以看到我必须为每种数据类型创建存储库。 (Foo,Baa,Daa等),其中CURD逻辑基本上与每个实例相同。所以我很自然地想要将存储库变成通用存储库。
2。为什么选择Singleton? 在不使用Singleton模式的情况下,每个新实例都会启动一个全新的重新加载内存缓存,这意味着新的本地数据库查询。在开发移动和内存受限设备(Android应用程序)时,每次设备更改配置/轮换时,这都会产生不必要的和I / O调用。仅仅想到这只是标志着我将不得不处理的巨大性能问题。因此,我认为只是懒惰实例化的全局可访问单个实例是一个加号。
我的尝试 因此,我开始创建Repository和Datasource接口的通用版本,并在每个数据类型实现Datasource接口时提供具体实现,如下所示:
class FooDatasource implements GenericDatasource<Foo>
{
//...
}
class BarDatasource implements GenericDatasource<Bar>
{
//...and so on and so forth
}
我目前的方法是单例模式,对于Java和特别是Android开发人员,使用Dagger 2的依赖注入可以更好地管理Generic实例。
答案 0 :(得分:2)
Generic类是否与Singleton Pattern兼容,即具有静态实例?
不,它不会那样工作,静态字段只存在一次,静态继承在Java中不存在。但是有很多不同的方法来实现单例。
不要这样做。 Singleton是一个反模式,主要是因为它对于测试目的而言非常糟糕。相反,使用容器(Spring,Guice,EJB等)为您管理单例,确保只存在一个实例。首先阅读Dependency Inversion Principle和Inversion of Control。如果是这样,我有以下要转换为Singleton的Generic类。什么是最佳做法?
(初学者问题)有没有一种很好的方法可以在运行时取消生成类的实例?将类作为参数传递给getInstance()?
是的,将类传递给getInstance实际上会使它更好一点,特别是如果你在内部使用类到实例映射(Guava has such a type)
答案 1 :(得分:1)
不要滥用单身人士。它们是您可能尝试实施的第一种模式,因为它是每本书中的第一种模式,但它几乎总是至少无用,至多是性能瓶颈和糟糕的设计决策(不是非常OO)
修改强>
你假设每个新实例无法共享同一个缓存基本上是错误的,原因有两个:
单例也有一个很大的问题:它直接负责实例化对象,即直接使用new
关键字。这很痛苦,因为您无法在运行时更改实现的concret类型(用于测试目的或任何其他用途)。查看工厂/工厂方法模式,以查看在运行时更改类型的更好方法。
你可以做的是拥有一个抽象的基类,通用,你的混凝土dao将扩展(但那些不是通用的)。像这样:
abstract class AbstractDao<ID, T> {
private Class type;
protected AbstractDao(Class type) {
this.type = type;
}
void save(T entity) {
// save an entity
}
T get(ID pkey) { /* get an entity */}
...
}
public class DaoX extends AbstractDao<Long, X> {
DaoX() {
super(X.class)
}
/* Empty! or only methods applicable for X */
}
public class DaoY extends AbstractDao<Integer, Y> {
DaoY() {
super(Y.class)
}
/* Empty! or only methods applicable for Y */
}
在这种情况下,您不会复制任何代码。