簡體   English   中英

在 inheritance 層次結構中創建每個 class 的單個實例

[英]Creating single instances of each class in the inheritance hierarchy

假設存在三個類,即A、BC ,使得B 擴展 AC 擴展 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();


我希望我清楚要求

問題

我們已經確定子類隱式調用超級構造函數,而超級構造函數作為回報拋出。

1. Singleton/工廠方法解決方案

您想要實現的被描述為 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工廠方法。 如果是多線程環境,要注意同步


2.收集最頂層的所有實例

另一個晦澀的解決方案是收集頂級父級中的所有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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM