![](/img/trans.png)
[英]Single table inheritance strategy (or table per class hierarchy) with Oracle and Hibernate
[英]Creating single instances of each class in the inheritance hierarchy
假設存在三個類,即A、B和C ,使得B 擴展 A , C 擴展 B 。
要求是客戶端代碼應該只能成功調用每個 class 的構造函數一次。 在嘗試調用構造函數兩次時,它應該拋出一個異常。
如果子類中不允許重復代碼,我該如何在 Java 中實現這一點?
例子:
public class A {
private static A instance;
public A() {
if (instance != null) {
throw new IllegalArgumentException();
}
instance = this;
}
}
public class B extends A {
private static B instance;
public B() {
if (instance != null) {
throw new IllegalArgumentException();
}
instance = this;
}
}
public class C extends B {
private static C instance;
public C() {
if (instance != null) {
throw new IllegalArgumentException();
}
instance = this;
}
}
public class Driver {
public static void main(String[] args) {
A a1 = new A();
B b1 = new B(); //throwing IllegalArgumentException, it should not throw
}
}
我試過的東西。
維護相應 class 類型的私有 static 引用,該類型最初設置為 null。 在構造函數塊中,我添加了 null 檢查以將此引用分配給 static 引用。 沒有工作,因為我無法避免重復代碼。
要求
//this should work fine
A a1 = new A();
B b1 = new B();
C c1 = new C();
---------------
//this should throw runtime exception
A a1 = new A();
A a2 = new A();
B b1 = new B();
---------------
//this should throw runtime exception
A a1 = new A();
B b1 = new B();
B b2 = new B();
---------------
//this should throw runtime exception
A a1 = new A();
B b1 = new B();
C c1 = new C();
C c2 = new C();
我希望我清楚要求
我們已經確定子類隱式調用超級構造函數,而超級構造函數作為回報拋出。
您想要實現的被描述為 Singleton 設計模式。 它在概念上需要一個static
成員。 Static 字段和/或方法(如果您想使用工廠方法)不會被繼承,因此操作 static 字段的代碼的重復是不可避免的。
您應該使用重復的空檢查和存儲 static 實例技術,它被廣泛使用和接受。 代碼重復的數量很少,你不應該害怕它。
對隱式超級構造函數調用進行了編輯:您可以使用條件(如A
中)或工廠方法(如B
中)。
public class A {
private static A instance;
public A() {
if (this.getClass() == A.class) {
if (instance != null) {
throw new IllegalArgumentException();
}
instance = this;
}
}
}
public class B extends A {
private static B instance;
private B() { }
public static B getInstance() {
if (instance != null) {
throw new IllegalArgumentException();
}
return instance = new B();
}
}
public class C extends B {
private static C instance;
public C() {
// check if (this.getClass() == B.class) when someone extends C
if (instance != null) {
throw new IllegalArgumentException();
}
instance = this;
}
}
public static void main(String[] args) {
A a1 = new A();
B b1 = B.getInstance();
C c1 = new C();
}
或者,您可以聲明一個private
構造函數並擁有一個static
工廠方法。 如果是多線程環境,要注意同步。
另一個晦澀的解決方案是收集頂級父級中的所有Class<>
實例並檢查構造函數中的重復性。 這不是一個
好的
傳統解決方案。 單例模式很常見。
public class TopClass {
private static final Set<Class<? extends TopClass>> instances = new HashSet<>();
public TopClass() {
if (instances.contains(this.getClass())) {
throw new IllegalArgumentException();
}
instances.add(this.getClass());
}
}
public class SubClass extends TopClass {}
public class AnotherClass extends SubClass {}
這樣,您將所有未來的子類限制為僅實例化一次。 這是限制性的,但是是的 - 更少的代碼行。
我想您可以創建一組已經初始化的類,並在每次構建新類時檢查它。 它允許創建一個A 實例、一個B 實例和一個C 實例。
class A {
private static final Set<Class<? extends A>> calledInitializations = new HashSet<>();
A() {
checkForSecondInit(A.class);
}
protected void checkForSecondInit(Class<? extends A> clazz) {
if (isNotInSuperClassOf(clazz)) {
if (calledInitializations.contains(clazz)) {
throw new RuntimeException("Second init in " + clazz.getName());
} else {
calledInitializations.add(clazz);
}
}
}
private boolean isNotInSuperClassOf(Class<? extends A> clazz) {
return getClass() == clazz;
}
}
class B extends A {
B() {
checkForSecondInit(B.class);
}
}
class C extends B {
C() {
checkForSecondInit(C.class);
}
}
嘗試這個。
class A {
private static boolean created = false;
A() {
if (getClass() == A.class) {
if (created) throw new IllegalStateException();
created = true;
}
}
}
class B extends A {
private static boolean created = false;
B() {
if (getClass() == B.class) {
if (created) throw new IllegalStateException();
created = true;
}
}
}
class C extends B {
private static boolean created = false;
C() {
if (getClass() == C.class) {
if (created) throw new IllegalStateException();
created = true;
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.