简体   繁体   English

避免静电场的最佳实践

[英]best practice to avoid static fields

I've already read some questions about the disadvantages of static variables (for example why are static variables considered evil , but i find some difficulties in choosing the best solution to avoid to use them. 我已经阅读了一些有关静态变量的缺点的问题(例如, 为什么静态变量被认为是邪恶的 ,但我发现在选择最佳解决方案以避免使用它们时遇到了一些困难。

In my simple chess application, for example, i have an abstract class, Piece, with many subclasses. 例如,在我的简单国际象棋应用程序中,我有一个抽象类Piece,其中包含许多子类。 Every Piece must have a BufferedImage variable, image , but i want to load every image just one time for each Piece. 每个片断都必须有一个BufferedImage变量image ,但是我想为每个片断仅加载一次图像

This would be very easy by using static variables, something like that : 通过使用静态变量,这将非常容易:

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;
    }
}

Of course this code doesn't follow OOP, and inheritance is not used for the image variable. 当然,此代码不遵循OOP,并且继承不用于image变量。

A solution would be to load all the images in an external class, and let all the subclasses instances to keep the reference to the same object: 一种解决方案是将所有图像加载到外部类中,并让所有子类实例保持对同一对象的引用:

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);
        // ...
    }
}

But what if i need to create the subclasses instances from n different classes ? 但是,如果我需要从n个不同的类中创建子类实例,该怎么办? The images would be loaded at least n times, assuming i create just one instance of those n classes. 假设我仅创建这n个类的一个实例,则图像将至少加载n次。

I've considered to keep the images reference in a Singleton pattern designed class, but i also want to keep the image variable in the Piece class to simply use the getImage() method for every Piece. 我已经考虑过将图像引用保留在Singleton模式设计的类中,但我也想将图像变量保留在Piece类中,以便对每个Piece都简单地使用getImage()方法。

Is it a good design to use the second solution combined with the Singleton pattern, so i would pass to every Piece's subclass constructor the reference to the same BufferedImage obtained with a method like SingletonClass.getXxxImage()? 将第二种解决方案与Singleton模式结合使用是否是一个好的设计,因此我会将对通过SingletonClass.getXxxImage()方法获得的相同BufferedImage的引用传递给每个Piece的子类构造函数?

Or is there any better approach? 还是有更好的方法? Of course it would be not so evil to load a BufferedImage more than one time, but i would like to have a general solution to avoid useless repetitions of code. 当然,多次加载BufferedImage并不是很邪恶,但是我想有一个通用的解决方案来避免代码的无用重复。

Thanks for your help ! 谢谢你的帮助 !

There are a few cases where static is the way to go. 在某些情况下, static是必经之路。 But generally, the need for static stuff signals a flaw in the OO design. 但是通常,对静态内容的需求表明OO设计存在缺陷。

In your particular case, I think you're missing an abstraction for the PieceType . 在您的特定情况下,我认为您缺少对PieceType的抽象。 If you model each piece type as a class, you're mixing the need for instantiating piecing with the general description of some particular kind of piece. 如果将每个样件类型建模为一个类,则将实例化拼接的需求与某种特殊样件的一般描述混合在一起。

Namely, your two bishops need to share both data (the image) and behavior (the moving pattern) that are not specific to the white or black bishop, but are common for bishops in general. 即,您的两个主教需要共享不特定于白色或黑色主教的数据(图像)和行为(移动模式),但通常对于主教来说是共享的。

While the shared behavior fits quite nicely into a class as a method definition (that will be shared by all instances), the shared data will need to be static or copied redundantly for each instance. 尽管共享的行为非常适合作为方法定义的类(将由所有实例共享),但是共享的数据将需要是static或为每个实例冗余地复制。

What may be missing here is some PieceType abstraction encapsulating both the data and the behavior of each kind of piece. 这里可能缺少的是一些PieceType抽象,它封装了PieceType的数据和行为。

This can be modeled as an enum (since you have a fixed number of types) listing each type of piece as an instance: 可以将其建模为一个枚举(因为您有固定数量的类型),将每种类型的零件作为实例列出:

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

}

Now you only need a single Piece type that will delegate all the type-related stuff to its PieceType: 现在,您只需要一个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
}

Note that the enum defined above inherently creates static variables (its constants). 请注意,上面定义的enum会固有地创建static变量(其常量)。 But this is one of the acceptable/encouraged usages for static (as I mentioned in the introduction). 但这是static的可接受/鼓励的用法之一(正如我在简介中所提到的)。

Note that static variables are not bad in and of themselves. 注意, static变量本身并不坏。 They just tend to get overused by new programmers who do not understand OOP. 他们只会被不了解OOP的新程序员过度使用。 This situation actually seems like a reasonable use of a static field. 实际上,这种情况似乎是对static字段的合理使用。 Every Bishop has the exact same visual, so it seems wasteful to load the same image multiple times. 每个Bishop都有完全相同的视觉效果,因此多次加载相同的图像似乎很浪费。

On the other hand, passing in an image to the constructor is more flexible. 另一方面,将图像传递给构造函数更灵活。 It leaves the responsibility of image loading to someone else. 它将图像加载的责任留给了其他人。 It also allows you to change the image used more easily. 它还使您可以更轻松地更改使用的图像。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM