我已经读过一些关于静态变量缺点的问题(例如why are static variables considered evil),但我发现在选择避免使用它们的最佳解决方案时遇到了一些困难。
在我的简单国际象棋应用程序中,例如,我有一个抽象类,Piece,有许多子类。 每件必须有一个BufferedImage变量,图像,但是我想为每件作品加载每张图片。
使用静态变量非常容易:
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类中保留 image 变量,只需使用getImage()方法每一件。
使用与Singleton模式结合的第二个解决方案是一个好的设计,所以我会向每个Piece的子类构造函数传递对使用SingletonClass.getXxxImage()等方法获得的相同BufferedImage的引用吗? / p>
还是有更好的方法吗?当然,多次加载BufferedImage并不是那么邪恶,但我希望有一个通用的解决方案来避免无用的重复代码。
感谢您的帮助!
答案 0 :(得分:3)
在某些情况下static
是可行的方法。但一般来说,对静态材料的需求标志着OO设计的一个缺陷。
在您的特定情况下,我认为您错过了PieceType
的抽象。如果您将每个片段类型建模为一个类,则需要将实例化拼接与某些特定片段的一般描述混合在一起。
即,你的两位主教需要分享不是白人或黑人主教特有的数据(图像)和行为(移动模式),但对于一般的主教来说是常见的。
虽然共享行为非常适合作为方法定义(将由所有实例共享)放入类中,但共享数据需要为static
或为每个实例冗余复制。
这里可能缺少的是一些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
可接受/鼓励的用法之一(正如我在引言中提到的那样)。
答案 1 :(得分:1)
请注意,static
变量本身并不坏。他们只是倾向于被不懂OOP的新程序员过度使用。这种情况实际上似乎是合理使用static
字段。每个Bishop
都具有完全相同的视觉效果,因此多次加载相同的图像似乎很浪费。
另一方面,将图像传递给构造函数更灵活。它将图像加载的责任留给了其他人。它还允许您更轻松地更改使用的图像。