2010-07-15 53 views
10

我经常遇到某种情况可能出现问题的情况,但由于例外情况并非如此,因此使用异常是不对的。有些事情可能会出错,但它并不是一个例外

例如:

我在设计一个垄断游戏。班级有一个方法buyHouse和一个计算剩余房屋数量的字段(有32个房屋在垄断中)。有可能出错的是一个玩家在剩下0时买房子。我应该如何处理这个问题。这是我能想出的3种方法。

1. public void buyHouse(Player player, PropertyValue propertyValue) 
{ 
    if(houseCount < 0) throw new someException; 
    .... 
    //Not really an exceptional situation 
} 

2. public boolean buyHouse(Player player, PropertyValue propertyValue) 
{ 
    if(houseCount < 0) return false; 
    .... 
    //This I think is the most normal approach but changing something 
    //and returning if it was a success seems bad practice to me. 
} 

3. public boolean housesLeft() 
{ 
    if(houseCount > 0) return true; 

    return false; 

    //Introducing a new method. But now I expect the client to call this method 
    //first before calling buyHouse(). 
} 

你会怎么做?

+0

而不是如果(东西是真的)返回true;返回false;我宁愿做最后的布尔retVal; retVal = houseCount> 0;返回(retVal); – TofuBeer 2010-07-15 19:28:49

回答

12

我会一起做3和1。 API的正确用法是在购买之前检查是否还有房屋。但是,如果开发人员忘记了这么做,那就抛出一个运行时异常。

如果这是一个多线程的情况(许多人同时购买房屋),它变得更加复杂。在这种情况下,我确实会考虑检查异常,如果不是tryToBuyAHouse方法返回一个布尔值,而是buyHouse方法的运行时异常。

+2

我也会这么说。我认为IllegalStateException是适当的。 – 2010-07-15 02:05:36

+0

谢谢 - 这似乎是正确的选择。 – 2010-07-15 11:56:23

4

我觉得“例外”的意思是相当主观的。这意味着任何你想要的意思。您正在设计该功能的界面,您可以决定什么是特殊的,哪些不是。

如果您不希望houseCount为< = 0时调用buyHouse,那么这里有个例外。即使你确实期望它被调用,你也可以在调用者中捕获异常来处理这种情况。

2

(1)或(2)是可以接受的,取决于您是否认为“无房买”的例行结果或特殊情况。

(3)是一个坏主意,有以下几个原因:

  • 它打破封装(客户端必须知道太多关于银行内部)
  • 你还是要检查错误做(1)或(2)的情况下,客户砸了
  • 它在多线程情况下
+0

我没有看到2与3不同,只是更糟 - 如果你忘记检查,你可以认为你买了房子,当你没有。 – Yishai 2010-07-15 01:31:23

+1

我不认为期望客户知道并按照游戏规则进行游戏并不合适。 – 2010-07-15 02:10:03

1

我会做这样的事情是有问题的:

public boolean BuyHouse(Player player, PropertyValue propertyValue) { 
     // Get houseCount 
     if(houseCount <= 0) { 
     // Log this to your message queue that you want to show 
     // to the user (if it has a UI) 
     return false; 
     } 
     // Do other stuff if houses are left 
} 

PS:我不熟悉Java,我使用C#

1

这个问题是很难没有这些实体有-一个房子的情况下回答。从一般的设计角度来看,(1)和(2)之间的调用者之间语义上的差异很小 - 都是尝试和检查 - 但是你认为(1)应该避开完全可预期的状态。

3

如果连续32次按预期工作,然后无法按预期运行,我认为如果它是一个孤立的情况,可以证明它是一个例外条件。

考虑到你描述的情况,我认为使用例外是不合适的,因为一旦售出32套房子,银行将继续退出(这是新的“正常”状态),而异常处理实际上是与正常处理相比,Java非常慢。

你可以做的一件事是更真实地反映实际的互动。在大富翁中,银行家只会告诉你,如果没有剩下的话,你就不能买房。

这种潜在的模型如下:

public House buy(Player player, PropertyValue propertyValue) { 
    House propertyHouse = null; 
    if (houseCount > 0) { 
    propertyHouse = new House(player, propertyValue); 
    houseCount--; 
    } 

    return propertyHouse; 
} 

这也将允许您添加行为,房屋目标,并请求/买房子多了几分自然的流动。如果没有可用的房屋,你不会得到一个。

+0

我认为这是正确的方向,但我宁愿使用Option类型(请参阅http://functionaljava.org)来强制您检查结果,避免NPE – Landei 2010-07-15 08:52:14

+0

这是一个有趣的方向,我可以看到一些优势那里。你有没有在日常编程中看到过这种范式的重要用途,或者这是更多的学术/研究工具吗? – mlschechter 2010-07-17 01:27:36

1

你决定的规则在这里为用户&例外谁使用您的API /方法:

housesLeft()可以称得上检查 留下的房屋数量 buyHouse()被调用之前。拨打 buyHouse()只要 房屋剩下的数量为零就是一个例外。

它与在访问某个数组元素之前进行检查类似,您在尝试访问它之前检查数组长度,否则将出现异常。

所以它应该是这样的:

if (housesLeft() > 0) buyHouse(...); 

类似

for (int i=0; i < arrayList.length; i++) System.out.println(arrayList[i]); 
+1

这种模式很容易出现多线程问题。 – samitgaur 2010-07-15 01:38:49

+0

@samG:是的,它很简单,但可以与其他线程相关的模式结合使用。我认为多线程在这里并不是bobjink关心的问题。 – ttchong 2010-07-15 03:32:41

+0

我觉得易has在多线程相关案例上面发布了一个很好的建议。 – ttchong 2010-07-15 03:36:25

2

其他几个选项:

  • 你的方法可能会接受一些房屋要求的参数,并检查玩家的可用余额和麻木后返回实际购买的房屋数量呃可用的房屋。返回零将是一个完全可以接受的可能性。当然,你依靠调用代码来检查实际返回的房子数量。 (这是关于返回布尔值的变体,当然,真/假指示购买的房屋为1或0)

  • 该主题的变体将返回与房屋成功数目对应的House对象的集合购买,这可能是一个空的集合。大概调用代码将无法表现,就好像它有更多House对象比你给它。 (这是返回House对象的变体,其中null表示没有购买房屋,并且对象代表1个房屋,并且通常是将空集合引用为空引用的一般编码方法的一部分)

  • 您的方法可能会返回HousePurchaseTransaction对象,该对象本身可查询以确定事务的成功或失败,实际成本等。

  • 关于这一主题的更丰富的变化可能使HousePurchaseTransaction抽象,并得出两个子类:SuccessfulHousePurchaseFailedHousePurchase,所以你可以在不同的行为与这两个结果的条件相关联。将房子安装到街道上可能需要您传递“SuccessfulHousePurchase”对象才能继续。 (这避免返回一个空为后一空引用错误的根本的危险,并且是在空对象模式的变体)

在现实中,我怀疑采取将取决于您结束在那里的办法分配责任将房子安置在董事会上,升级到酒店,执行平等规则,限制在特定街道上购买房屋的数量等等。

+1

一些很好的建议,我没有想到:) – 2010-07-15 11:53:58

5

这与从一个空栈中弹出一个项目的想法非常相似......这是例外。你正在做一些应该失败的事情。

考虑一些特殊情况,例如,如果您想通知程序员出现问题,并且您不希望他们忽略它。由于程序员可以忽略它,因此使用简单的布尔返回值不是“正确的”。还有一个想法,那就是应该调用一个方法来检查是否有可用的房屋,这是一个好主意。但请记住,程序员在某些情况下会忘记调用它。在这种情况下,这种例外是为了提醒他们,在获得房屋之前,他们需要调用该方法来检查房屋是否存在。

因此,我会提供方法来检查是否有房屋,并期望人们会调用它并使用真/假返回值。如果他们没有调用该方法,或者忽略返回值,我会抛出一个异常,以便游戏不会处于不良状态。

1

记住,你可以使用

return houseCount > 0; 

而不是

if(houseCount > 0) return true; 

return false; 
+0

我知道,但我更喜欢我的方式:) – 2010-07-15 16:29:24

相关问题