繁体   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