【问题标题】:Is this an acceptable use of instanceof?这是可以接受的 instanceof 用法吗?
【发布时间】:2014-07-12 04:10:53
【问题描述】:

我正在研究卡牌游戏 UNO 的实现(主要是运行模拟以测试一些房屋规则,但那是另一回事)。

对于那些从未玩过它的人来说,它类似于 Crazy Eights。玩家轮流在弃牌堆上打一张牌。卡片必须在数量或颜色上匹配。还有抽牌,迫使下一个玩家抽两张或四张牌。它对家规也很友好,这让它很有趣。

我有一个带有valuecolor 卡的Card 类。我想做的是创建扩展CardDrawCard。然后,在确定游戏机制时,我会使用instanceof 来测试我是否有DrawCard

我知道instanceof 经常有问题,但这对我来说似乎没问题。通常卡片的处理方式相同,只有少数特殊卡片会受到不同的处理,并且仅在特定于卡片类型的特殊情况下(虽然这似乎是一个滑坡的事情......)

我可以只在Card 类中使用标记(实际上,每种类型的卡都已经有自己的“值”),但无论如何我都在扩展Card,以便拥有其他类型的卡可以使用的一些方法有(这不仅仅是一种识别手段)。使用instanceof 对我来说似乎更通用,因为我不需要知道value 的哪些值需要这种特殊行为,例如,将 Draw 8 卡添加到绘制 2 和绘制 4。(这么说让我想知道是否可以使用某种嵌套枚举或其他东西,但我不知道)

我知道这两种解决方案都可以工作(让程序运行)。对我来说使用instanceof 感觉更好,但我没有经验来理解它是否可以。这是糟糕的设计吗?

【问题讨论】:

  • 你觉得这篇文章的答案很有帮助:[在 Java 中使用 instanceof 的性能影响][1] [1]:stackoverflow.com/questions/103564/…
  • “抽奖”卡(不是类)是否也有值颜色?如果不是,那么继承不是这里的正确解决方案——继承是一种“是”关系。请注意,如果“抽牌”卡确实具有值或颜色,则它们必须具有完全相同的语义才能被考虑。
  • @acdcjunior 是的,抽牌有颜色

标签: java oop instanceof


【解决方案1】:

简短的回答:不是真的可以接受,所以是的 - 这是设计缺陷的标志。 instanceof 几乎总是一种气味,除非在极少数情况下,图书馆试图提供某种元或其他丑陋但有助于克服语言/环境缺陷的帮助。

根据这种观点,这个问题有点重复。查看答案:

When is it acceptable to use instanceof?

建议使用访问者模式。如果您确实在系统中有两种不同的类型,这可能是正确的。

您也不必“显式”使用访问者模式,而是将其合并到您的程序流程中。所以考虑一个接口卡:

interface Card {
  void pick(Player player);
}

class DrawCard implements Card {
  void pick(Player player) {
    player.draw(value); // assume value passed in e.g. ctor
  }
}

【讨论】:

  • OK 这说得通。我的游戏当前设置的方式,游戏控制类将卡片传递给玩家的 play 方法。那么我可以在 Card 接口中放置方法来确定卡的属性吗?类似于“下一个看到这张牌的玩家必须抽牌”的布尔方法吗?
  • 没关系,我只要让玩家响应获得一张牌,然后“挑选”这张牌(如果更有意义,您可以将其重命名为 onTaken 或类似名称),但随后让卡实现调用玩家上的方法以继续回合。这可能意味着给玩家加分(player.increaseScore)或告诉玩家他们必须做更多的事情(player.takeMoreCards)。
【解决方案2】:

我会说一般来说最好尽可能避免instanceof

虽然由于您没有发布任何实际代码而有些模糊,但在这种情况下,一种选择是实现两个不同的接口,例如 ICardIDrawCard 并拥有Card 类实现了ICard 接口,DrawCard 类实现了这两个接口

那么你就可以通过函数签名等中的接口来区分DrawCard类(即,将其称为类型的对象) em>IDrawCard)。

根据 OP 的评论进行编辑:

在打出卡片后处理动作方面,您可以利用接口覆盖处理动作的函数。既然这是上下文,我可能会推荐三个不同的接口:

  1. ICommonCard
  2. ICard
  3. IDrawCard

其中ICommonCard 是通用接口,当您需要处理一些通用方法时,其他两个接口处理这两种特定类型的需求。

然后假设您有一个名为handleAction 的动作处理程序方法,可以这样定义:

void handleAction(ICard card)
{
    // do ICard stuff here
    return;
}

void handleAction(IDrawCard card)
{
    // do IDrawCard stuff here
    return;
}

然后,当您调用该函数时,您可以将接口类型的对象传递给重载函数(一种选择是为每种类型都有一个成员变量,如果它是一个或另一种,将不是null 的那个传递给函数)。

【讨论】:

  • 谢谢,我可能应该使用接口。但是,如何使用 instanceof 来识别它们?
  • 嗯,这真的取决于你想要做什么。正如我上面所说,您可以通过它们在函数签名等中的接口来引用它们,这样可以帮助区分。具体是什么背景?
  • 卡片有不同的行为,比如卡片被打出后会发生什么。我需要知道牌的类型是什么,这样我才能确定在打出最后一张牌后什么是有效动作。
猜你喜欢
  • 2011-11-19
  • 1970-01-01
  • 1970-01-01
  • 2017-06-14
  • 1970-01-01
  • 1970-01-01
  • 2010-10-10
  • 2017-07-04
  • 2011-03-20
相关资源
最近更新 更多