gpt4 book ai didi

java - MVC架构中如何避免使用instanceof

转载 作者:行者123 更新时间:2023-12-01 16:45:24 26 4
gpt4 key购买 nike

我正在用 Java 开发像 Pacman 这样的游戏,目前我正面临着这些我不喜欢的代码味道。

让我解释一下我的想法:我的游戏是建立在MVC架构上的。在 View 模块上,我查找模型上的每个电源,并将其添加到要在 GUI 上绘制的元素列表中。问题是我有 3 种使用接口(interface)的电源,因此当我添加电源时,我需要检查它们是什么类型,然后添加相应的 View 。让我展示一些代码,这样我就可以更清楚了:

for (PowerUp powerUp : level.getPowerUps()) {
if (powerUp instanceof Invincibility) elements.add(new InvincibilityView(powerUp.getPosition()));
if (powerUp instanceof Freeze) elements.add(new FreezeView(powerUp.getPosition()));
if (powerUp instanceof Fright) elements.add(new FrightView(powerUp.getPosition()));
}

第二种气味与鬼魂有关,我的游戏有状态模式,如果状态改变,应该改变鬼魂的颜色。例如,如果状态为“Frightened”,我希望鬼魂为橙色,如果状态为“Frozen”,我希望鬼魂为蓝色,等等。

因此,在创建 Ghost View 时,我通过参数传递状态,并检查(再次使用 instanceof)当前处于什么状态。让我展示更多代码:

public void draw(graphics) {
String color = "#FF0000";
if (state instanceof Invincible) color = "#585858";
if (state instanceof Frozen) color = "#00FFFF";
if (state instanceof Frightened) color = "#FF7F50";
// draw ghost
}

我的问题是如何在不更改模型模块的情况下避免使用 instanceof

注意安全!

最佳答案

当您旨在隔离关注点时,这实际上是一个非常常见的需要解决的问题。例如,如果渲染没有与模型分离,那么您将拥有一个 PowerUp.render() 方法,以便它们可以自行渲染并结束。

但是,您会遇到另一个问题,即所有类型的问题最终都集中在一个类中。这是一种权衡,您要么直接在对象上实现操作,要么提取这些行为,但随后必须以某种方式执行类型匹配。

抽象工厂在这里可能很有趣,因为它减少了您必须做出的基于类型的决策的数量,但是如果您需要做出其他基于类型的决策(例如不同的启动声音),您将不得不再次类型匹配,就没有办法了。

话虽这么说,您可以使用 Visitor Pattern 实现可重用的类型安全机制来进行类型匹配。 .

例如(为简洁起见,省略了访问修饰符)

interface PowerUpVisitor {
visit(Invincibility powerUp);
visit(Freeze powerUp);
visit(Fright powerUp);
}

interface PowerUp {
accept(PowerUpVisitor visitor);
...
}

class Freeze implements PowerUp {
accept(PowerUpVisitor visitor) { visitor.visit(this); }
}

class PlayPowerUpSound implements PowerUpVisitor {
visit(Invincibility powerUp) { playInvicibilitySound(); }
...
}

class RenderPowerUp implements PowerUpVisitor {
visit(Invincibility powerUp) { renderInvisibility(); }
...
}

//In practice you would most likely reuse the same visitor instances
somePowerUp.accept(new PlayPowerUpSound()); //to play sound
somePowerUp.accept(new RenderPowerUp()); //to render

这种模式的主要优点是,现在编译器会告诉您是否忘记处理特定类型的启动,这与 instanceof 检查不同。

使用基于动态类型的解析(就像其他建议的抽象工厂解决方案一样),您必须使用反射来实现基于运行时的验证,以确保所有类型都存在工厂。

对于抽象语法树等分层结构,人们通常会自然而然地想到访问者模式,但它在这里同样有用。

如果您同意放松隔离,还有其他方法。例如,您可以为 PowerUp 可能具有的各种行为引入专用接口(interface),例如 IPlaySoundIHaveAView 等,并实现这些直接在powerups中进行操作。边界现在仅由界面绘制,但它们仍然存在。

最后,您还可以向 powerups 询问其各自的渲染器或声音播放器,而不是直接由对象执行操作。我想我更喜欢这里的访客,但是剥猫皮的方法有很多,具体取决于您期望的复杂性等。这都是关于权衡的!

关于java - MVC架构中如何避免使用instanceof,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61787453/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com