![](/img/trans.png)
[英]How can I implement ActionListener with a non abstract class? Java
[英]How can I implement an abstract singleton class in Java?
這是我的示例抽象單例類:
public abstract class A {
protected static A instance;
public static A getInstance() {
return instance;
}
//...rest of my abstract methods...
}
以下是具體實施:
public class B extends A {
private B() { }
static {
instance = new B();
}
//...implementations of my abstract methods...
}
不幸的是我無法在B類中獲取靜態代碼來執行,因此實例變量永遠不會被設置。 我試過這個:
Class c = B.class;
A.getInstance() - returns null;
還有這個
ClassLoader.getSystemClassLoader().loadClass("B");
A.getInstance() - return null;
在eclipse調試器中運行這兩個,靜態代碼永遠不會被執行。 我可以找到執行靜態代碼的唯一方法是將B的構造函數的可訪問性更改為public,並調用它。
我在Ubuntu 32bit上使用sun-java6-jre來運行這些測試。
摘要單身人士? 對我來說聽起來不太可行。 Singleton模式需要private
構造函數,這已經使子類化成為不可能。 你需要重新考慮你的設計。 抽象工廠模式可能更適合於特定目的。
你試圖讓一個抽象類扮演兩個截然不同的角色:
最重要的是,你還希望服務是單例並在整個類系列上強制執行'singletoness',因為某些原因你不考慮緩存服務實例。
有人(我會)說它聞起來非常糟糕,因為多種原因它違反了關注點,單身人士無法進行單元測試“等等。
其他人會說它沒關系,它不需要很多不同的基礎設施,並且在一些非常常見的第三方(傳統)Java API中有一些流暢的界面。
不好的部分要求孩子們選擇父工廠方法返回的實現。 這個責任應該被推高並集中到抽象的超類中。 否則,您將在非常不同的上下文中使用的模式混合在一起,抽象工廠(父級決定客戶將要獲得的類家族)和工廠方法(子工廠選擇客戶端將獲得的內容)。
Factory Method實際上也不可能,因為您不能覆蓋靜態方法或構造函數。
有一些(丑陋的)方法來實現你的目標:
public abstract class A{
public static A getInstance(...){
if (...)
return B.getInstance();
return C.getInstance();
}
public abstract void doSomething();
public abstract void doSomethingElse();
}
public class B extends A{
private static B instance=new B();
private B(){
}
public static B getInstance(){
return instance;
}
public void doSomething(){
...
}
...
}
//do similarly for class C
父級也可以使用反射,緩存實例等。
更加友好的測試和擴展解決方案只是標准的關注點分離。 這些孩子本身不再是單身,但你將它們打包成一些內部包,你將其記錄為“私有”,外部包中的公共抽象父將處理子實例的緩存或池化,強制執行任何實例化這些課程需要政策。
A.getInstance()
永遠不會調用派生實例,因為它是靜態綁定的。
我將對象的創建與實際對象本身分開,並創建一個返回特定類類型的適當工廠 。 目前尚不清楚你如何參數化,給定你的示例代碼 - 是通過一些參數進行參數化,還是類選擇是靜態的?
你可能想重新考慮單身,順便說一句。 這是一個常見的反模式 ,並使測試(特別是)成為一種痛苦,因為測試中的類將提供他們自己的該類實例作為單例。 您不能提供虛擬實現,也不能(輕松地)為每個測試創建新實例。
除了其他人指出的問題之外,在A
中使用instance
字段意味着在整個VM中只能有一個單例。 如果你還有:
public class C extends A {
private C() { }
static {
instance = new C();
}
//...implementations of my abstract methods...
}
...然后最后加載的B
或C
任何一個都將獲勝,而另一個的單例實例將丟失。
這只是做事的壞方法。
我發現了在抽象類中使用Singleton的更好方法,它使用靜態Map來維護子類的實例。
public abstract class AbstractSingleton {
private static Map<String, AbstractSingleton> registryMap = new HashMap<String, AbstractSingleton>();
AbstractSingleton() throws SingletonException {
String clazzName = this.getClass().getName();
if (registryMap.containsKey(clazzName)) {
throw new SingletonException("Cannot construct instance for class " + clazzName + ", since an instance already exists!");
} else {
synchronized (registryMap) {
if (registryMap.containsKey(clazzName)) {
throw new SingletonException("Cannot construct instance for class " + clazzName + ", since an instance already exists!");
} else {
registryMap.put(clazzName, this);
}
}
}
}
@SuppressWarnings("unchecked")
public static <T extends AbstractSingleton> T getInstance(final Class<T> clazz) throws InstantiationException, IllegalAccessException {
String clazzName = clazz.getName();
if (!registryMap.containsKey(clazzName)) {
synchronized (registryMap) {
if (!registryMap.containsKey(clazzName)) {
T instance = clazz.newInstance();
return instance;
}
}
}
return (T) registryMap.get(clazzName);
}
public static AbstractSingleton getInstance(final String clazzName)
throws ClassNotFoundException, InstantiationException, IllegalAccessException {
if (!registryMap.containsKey(clazzName)) {
Class<? extends AbstractSingleton> clazz = Class.forName(clazzName).asSubclass(AbstractSingleton.class);
synchronized (registryMap) {
if (!registryMap.containsKey(clazzName)) {
AbstractSingleton instance = clazz.newInstance();
return instance;
}
}
}
return registryMap.get(clazzName);
}
@SuppressWarnings("unchecked")
public static <T extends AbstractSingleton> T getInstance(final Class<T> clazz, Class<?>[] parameterTypes, Object[] initargs)
throws SecurityException, NoSuchMethodException, IllegalArgumentException,
InvocationTargetException, InstantiationException, IllegalAccessException {
String clazzName = clazz.getName();
if (!registryMap.containsKey(clazzName)) {
synchronized (registryMap) {
if (!registryMap.containsKey(clazzName)) {
Constructor<T> constructor = clazz.getConstructor(parameterTypes);
T instance = constructor.newInstance(initargs);
return instance;
}
}
}
return (T) registryMap.get(clazzName);
}
static class SingletonException extends Exception {
private static final long serialVersionUID = -8633183690442262445L;
private SingletonException(String message) {
super(message);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.