[英]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.