簡體   English   中英

避免靜電場的最佳實踐

[英]best practice to avoid static fields

我已經閱讀了一些有關靜態變量的缺點的問題(例如, 為什么靜態變量被認為是邪惡的 ,但我發現在選擇最佳解決方案以避免使用它們時遇到了一些困難。

例如,在我的簡單國際象棋應用程序中,我有一個抽象類Piece,其中包含許多子類。 每個片斷都必須有一個BufferedImage變量image ,但是我想為每個片斷僅加載一次圖像

通過使用靜態變量,這將非常容易:

abstract class Piece
{
    // ... 
    public abstract BufferedImage getImage();
}
class Bishop extends Piece
{
    private static final BufferedImage image = null;

    static{
        try{
            image = ImageIO.read(ClassLoader.getSystemResource("chess/img/pieces/Bishop.png"));
        }
        catch(IOException ex){
            // ...
        }
    }

    public BufferedImage getImage(){
        return image;
    }
}

當然,此代碼不遵循OOP,並且繼承不用於image變量。

一種解決方案是將所有圖像加載到外部類中,並讓所有子類實例保持對同一對象的引用:

abstract class Piece
{
    final BufferedImage image;
    public Piece(/* ... */ BufferedImage image){
        this.image = image;
    }
    public BufferedImage getImage(){
        return image;
    }
}
class Bishop extends Piece
{
    public Bishop(/* ... */ BufferedImage image){
        super(/* ... */ image);
        // ...
    }
}

但是,如果我需要從n個不同的類中創建子類實例,該怎么辦? 假設我僅創建這n個類的一個實例,則圖像將至少加載n次。

我已經考慮過將圖像引用保留在Singleton模式設計的類中,但我也想將圖像變量保留在Piece類中,以便對每個Piece都簡單地使用getImage()方法。

將第二種解決方案與Singleton模式結合使用是否是一個好的設計,因此我會將對通過SingletonClass.getXxxImage()方法獲得的相同BufferedImage的引用傳遞給每個Piece的子類構造函數?

還是有更好的方法? 當然,多次加載BufferedImage並不是很邪惡,但是我想有一個通用的解決方案來避免代碼的無用重復。

謝謝你的幫助 !

在某些情況下, static是必經之路。 但是通常,對靜態內容的需求表明OO設計存在缺陷。

在您的特定情況下,我認為您缺少對PieceType的抽象。 如果將每個樣件類型建模為一個類,則將實例化拼接的需求與某種特殊樣件的一般描述混合在一起。

即,您的兩個主教需要共享不特定於白色或黑色主教的數據(圖像)和行為(移動模式),但通常對於主教來說是共享的。

盡管共享的行為非常適合作為方法定義的類(將由所有實例共享),但是共享的數據將需要是static或為每個實例冗余地復制。

這里可能缺少的是一些PieceType抽象,它封裝了PieceType的數據和行為。

可以將其建模為一個枚舉(因為您有固定數量的類型),將每種類型的零件作為實例列出:

enum PieceType {
    BISHOP {
        @Override public void move() { /* whatever */ }
    },
    PEON {
        ...
    }

    private final BufferedImage image;

    PieceType() {
        image = ImageIO.read(ClassLoader.getSystemResource("chess/img/" + name().toLowerCase() + ".png"));
    }

    public abstract void move(); // or whatever

}

現在,您只需要一個Piece類型,它將所有與類型相關的東西委派給它的PieceType:

class Piece {
    private final PieceType pieceType;
    // position and all...

    Piece(PieceType pieceType) {
        this.pieceType = pieceType;
    }

    // behavior that delegates to the pieceType whenever necessary
}

請注意,上面定義的enum會固有地創建static變量(其常量)。 但這是static的可接受/鼓勵的用法之一(正如我在簡介中所提到的)。

注意, static變量本身並不壞。 他們只會被不了解OOP的新程序員過度使用。 實際上,這種情況似乎是對static字段的合理使用。 每個Bishop都有完全相同的視覺效果,因此多次加載相同的圖像似乎很浪費。

另一方面,將圖像傳遞給構造函數更靈活。 它將圖像加載的責任留給了其他人。 它還使您可以更輕松地更改使用的圖像。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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