[英]Is using a Singleton pattern good for large Generic classes in Java?
我是 Java 中泛型和单例模式的新手。 我有以下问题:
泛型类是否与单例模式兼容,即具有静态实例?
如果是这样,我有以下通用类要转换为单例。 最佳做法是什么?
(初学者问题)有没有一种在运行时对类的实例进行去泛化的好方法? 在 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;
}
}
我的单例泛型用例:
1. 为什么是泛型? 首先,假设我有以下单例存储库用于一种类型的数据,以下示例来自我在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. 为什么是单例? 如果不使用单例模式,每个新实例都会启动一个全新的内存缓存重新加载,这意味着新的本地数据库查询。 在为移动设备和内存受限设备(Android 应用程序)进行开发时,每次设备更改配置/旋转时都会产生不必要的 I/O 调用。 仅仅想到这一点就表明我必须处理一个巨大的性能问题。 因此,我认为仅延迟实例化的全局可访问单个实例是一个加分项。
我的尝试所以我着手创建 Repository 和 Datasource 接口的通用版本,并让每种数据类型在实现 Datasource 接口时提供具体的实现,如下所示:
class FooDatasource implements GenericDatasource<Foo>
{
//...
}
class BarDatasource implements GenericDatasource<Bar>
{
//...and so on and so forth
}
我目前的方法是使用 Dagger 2 通过依赖注入更好地管理通用实例的单例模式,适用于 Java 和特别是 Android 开发。
泛型类是否与单例模式兼容,即具有静态实例?
不,它不会那样工作,静态字段只存在一次,Java 中不存在静态继承。 但是有许多不同的方法来实现单例。
如果是这样,我有以下通用类要转换为单例。 最佳做法是什么?
不要这样做。 Singleton 是一种反模式,主要是因为它对于测试目的来说很糟糕。 相反,使用容器(Spring、Guice、EJB 等)为您管理单例,确保只有一个实例存在。 首先阅读依赖倒置原则和控制倒置。
(初学者问题)有没有一种在运行时对类的实例进行去泛化的好方法? 在 getInstance() 中将类作为参数传递?
是的,将类传递给 getInstance 实际上会使这更好一点,特别是如果您在内部使用类到实例映射( 番石榴有这样的类型)
不要滥用单身人士。 它们是您可能尝试实现的第一个模式,因为它是每本书中的第一个,但它几乎总是至少没用,最多是性能瓶颈和糟糕的设计决策(不是很面向对象)
编辑:
您假设每个新实例不能共享相同的缓存基本上是错误的,原因有两个:
单例还有一个非常大的问题:它直接负责实例化对象,也就是直接使用new
关键字。 这很痛苦,因为您无法在运行时更改实现的具体类型(出于测试目的或任何其他用途)。 查看工厂/工厂方法模式以了解在运行时更改类型的更好方法。
你可以做的是有一个抽象基类,泛型,你的具体 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 */
}
在这种情况下,您不会复制任何代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.