我的软件工程课上的一项作业是设计一个可以玩不同形式的特定应用程序的应用程序。有问题的游戏是Mancala,其中一些游戏称为Wari或Kalah。这些游戏在某些方面有所不同,但对于我来说,重要的是要知道这些游戏可能在以下方面有所不同:
- 移动结果的处理方式
- 确定游戏结束的方式
- 确定获奖者的方式
设计该功能的第一件事是使用策略模式,我在算法(游戏的实际规则)上有所不同。设计看起来像这样:
然后我对自己想,在Mancala和Wari的游戏中,确定获胜者的方式是完全相同的,并且代码会重复。我不认为这从定义上讲违反了“一条规则,一个地方”或DRY原则,因为Mancala规则的变化不会自动意味着在Wari中也应更改规则。然而,从我教授的反馈中,我印象深刻地找到了另一种设计。
然后我想到了这个:
每个游戏(Mancala,Wari,Kalah等)都将具有每个规则界面类型的属性,即WinnerDeterminer
,如果有Mancala 2.0版本与Mancala 1.0相同,除了如何确定获胜者之外,使用Mancala版本。
我认为将这些规则作为策略模式实施当然是有效的。但是,当我想进一步设计时,真正的问题就来了。
在阅读有关模板方法模式的信息时,我立即认为它可以应用于此问题。用户进行移动时所执行的操作始终相同,并且顺序相同,即:
- 在洞中放石头(所有游戏都一样,因此将在模板方法本身中实现)
- 确定举动的结果
- 确定游戏是否由于上一步而结束
- 如果游戏结束,确定谁赢了
最后三个步骤全部属于上述我的策略模式。合并这两项时,我遇到很多麻烦。我发现一种可能的解决方案是放弃策略模式并执行以下操作:
我真的没有看到策略模式与此之间的设计差异吗?但是我确定我需要使用模板方法(尽管我可以肯定必须使用策略模式)。
我也无法确定谁将负责创建TurnTemplate
对象,但是使用策略模式,我觉得我拥有对象族(三个规则),可以使用抽象工厂模式轻松创建对象族。然后MancalaRuleFactory
,我将拥有一个,WariRuleFactory
等等,他们将创建规则的正确实例并将其交给我RuleSet
。
假设我使用了策略+抽象工厂模式,并且我有一个RuleSet
对象,其中包含用于这三个规则的算法。我觉得仍然可以使用模板方法模式的唯一方法是将此RuleSet
对象传递给我TurnTemplate
。然后出现的“问题”是,我永远不需要的具体实现TurnTemplate
,这些类将变得过时。在我受保护的方法中,TurnTemplate
我可以调用ruleSet.determineWinner()
。结果,TurnTemplate
该类将不再是抽象的,而是必须变得具体,那么它仍然是模板方法模式吗?
总而言之,我是在以正确的方式思考还是在错过简单的东西?如果我处在正确的轨道上,如何将策略模式和模板方法模式结合在一起?