我正在尝试设计Bejeweled游戏。我基本上有3个班级。 Game
类,即播放器将使用的类,Board
类,代表电路板,以及SwitchController
类,负责检查是否需要切换在棋盘上是有效的,进行切换,计算可用的开关数量(所以我可以知道游戏何时结束等)。
我目前的设计如下:
Game:
isGameOver()
isSwitchValid(coord1, coord2)
makeSwitch(coord1, coord2)
getPieceAt(coord)
getBoardLength()
IBoard:
getPieceAt(coord)
setPieceAt(coord, piece)
getLength()
我的想法就是ISwitchController
:
ISwitchController:
isSwitchValid(coord1, coord2)
makeSwitch(coord1, coord2)
getAllValidSwitches()
这是一个关于如何组织类的小图:
我会有两个不同的具体类IBoard
可供使用(对于每一个,我都必须有ISwitchController
实现。
我的计划是实施2个IBoard:
第一个,ArrayBoard
,将所有板块存储在2D阵列中。没什么特别的。我将定义一个ArrayBoardSwitchController
来管理这个类。
第二个,ListBoard
,对于每种颜色的片段都有一个列表/集合,其中包含该颜色片段的所有坐标。我将定义一个ListBoardSwitchController
来管理这个类。
这里的主要问题是SwitchController
和ArrayBoard
上ListBoard
的实施完全不同。例如,虽然实现getAllValidSwitches()
ArrayBoardSwitchController
只需要getPieceAt()
方法,但这对ListBoardSwitchController
来说不是一个好主意(在该类中我使用内部列表,因为通过这种方式检查移动是否有效更容易。
从我所看到的,有两种不同的解决方案:
我可以将它们合并在一起
ISwitchController
和IBoard
接口。那种方式我只有
两个班,游戏和董事会(同时
基本上游戏只是一个
董事会的控制器,因为它
将是拥有所有人的董事会
游戏逻辑)。它不会那么好
因为班级不会
如果我有的话就像他们一样
3个不同的类别。
让接口按原样放置
我需要与公众合作的所有方法
在具体课程中。例如,如果我需要
一个getYellowPiecesList()
方法,我把它公之于众
在ListBoard
上,ListBoardSwitchController
可以
用它。 ListBoardSwitchController
只会
了解它,因为它知道它只有作用
反对ListBoards
。
您对此事有何看法? 这里的重点不是如何设计宝石迷阵游戏,而是如何解决这个问题,当你尝试实现算法时,这是经常出现的:一方面你想要有一个清晰和良好的OOP设计,并且在另一方面,有时会妨碍有一个健全有效的算法实现。
答案 0 :(得分:4)
这里的主要问题是SwitchBtroller的实现在ArrayBoard和ListBoard上完全不同。
如果是这种情况,那么听起来您没有充分设计IBoard
接口,以便类可以在不知道实现细节的情况下使用IBoard
的实现。如果IBoard
的用户需要知道正在使用什么实现,那么它几乎就会失去拥有接口的目的!
我强烈建议重新访问您在IBoard
上公开的方法,看看是否有一种方式可以以更通用的方式公开类似“以此坐标获取该片段”的内容。确保控制器需要在IBoard
实例上调用的任何方法仅 IBoard
接口中的方法。
例如,虽然为了实现getAllValidSwitches(),ArrayBoardSwitchController只需要getPieceAt()方法,但这对ListBoardSwitchController来说不是一个好主意(在该类中我使用内部列表,因为它更容易检查移动是否有效那样)。
如果诸如“获取此坐标的片段”之类的操作对IBoard
接口有用,那么实现必须忠实于他们的合同并正确实现它。听起来好像您的ListBoard
没有忠实地履行IBoard
中规定的合同。
答案 1 :(得分:3)
3:让ArrayBoardSwitchController和ListBoardSwitchController成为ArrayBoard和ListBoard的内部类。控制器的实现与电路板的实现有关,因此将它们保持在一起是有意义的。因为控制器是内部类,所以您可以使用板上的实现细节。然后使其工作扩展IBoard接口以返回ISwitchController。
请注意,这与选项1略有不同。(现在可以从IBoard间接使用ISwitchController,合并它们可以直接访问ISwitchController)
答案 2 :(得分:1)
ListBoard作为与ArrayBoard分离的对象的目的是什么?如果我要打扰宝石列表,我会将它保存在一个对象中,该对象也包含每个位置的数组,以便可以快速有效地交换两个宝石的位置。不管怎么说我还清楚为什么你需要这个位置列表?
如果运行速度为1.19Mhz的6507具有128字节的RAM和20%的CPU可用性可以处理列,在不到100ms的时间内在6x20上找到所有3-in-a-row组合,我认为更现代的机器可以扫描对于移动可接受的快速而不使用什么宝石列表在哪里。我建议填充您的电路板阵列,这样您就不必担心边缘情况,并且每个宝石检查16个不同单元格的组合(*),看看它们是否都匹配。有些动作可能会被双重报告(例如,此算法可能会检测到向左移动宝石会创建一个3行,并且还会检测到将宝石移动到右边第一个的左边会创建一个3英寸-a-row)但这应该不是问题。
(*)如果宝石可以向左移动,那么它必须匹配目的地左边的两颗宝石,或目的地上方的两颗宝石,或下面的两颗宝石,或上面的一颗宝石和下方的宝石。同样适用于其他方向。