2008-09-18 67 views
7

我一直在想了一会儿这个面向对象的设计问题,现在都无法拿出一个满意的解决方案,所以想我应该把它开到人群这里一些意见。OO设计,开/常闭原则问题

我有一个游戏类代表一个回合制棋盘游戏,我们可以假设它类似于这个问题的垄断。 在我的设计,我有一个包含方法TakeTurn一个球员类。

游戏遍历所有球员 S和调用TakeTurn方法做一切必要的事情来完成转弯。 我想能够拥有n个玩家,并且能够将他们的任意数量设置为电脑玩家。 所以,我的想法是有一个HumanPlayer类和一个类,这两个类都派生自Player。

游戏只知道球员,并简单的呼吁依次在每个球员TakeTurn方法。 我的问题在于事实上,物体可以完全自动化,即与Monopoly示例保持一致,可以决定使用某些逻辑来购买物业。 现在,随着HumanPlayer对象,它需要得到实际用户的输入,能够买实例中的属性,这似乎意味着不同的接口,可能意味着他们不应该得到

我一直没能拿出一个很好的解决问题,而不必在游戏类了解各种播放器的实际实现类中明确。我总是可以假设在游戏中,只有人类和电脑玩家才会这样做,并且有效地关闭它以延伸,但它看起来并不是很好的OO编程。

对此的任何意见将不胜感激。

+0

我不确定[tag:open-closed-principle]在这里适用。 – Fuhrmanator 2012-04-18 12:51:43

回答

7

我认为你不应该让Game类处理IO。这种方式,(阻挡)TakeTurn方法将会从游戏板中隐藏执行的手段。它可以使用其他对象与用户进行通信。

所有的游戏类应该关注的是董事会的状态和转折点。玩家都应该实现一个单一的球员界面,并隐藏游戏中的所有实施。

+0

+1努力提供游戏良好*凝聚力*(适当的责任)。 – Fuhrmanator 2012-04-18 12:50:22

1

与其告诉游戏类,只有永远一个人,为什么不让它在游戏的菜单/初始化过程中获取输入?如果有更多的玩家,那么可以通过某种形式的输入来决定(在菜单中选择玩家),在游戏类初始化之前。

0

我觉得Game类不应该对玩家级别任何实现的关注,同时也忽略了用户界面。

任何用户输入需要通过HumanPlayer类进行处理。

1

球员呈现给游戏接口垂直于衍生球员类的行为。

该实现的TakeTurn取决于具体类型的球员对象不应该是令人担忧的事实。

0

林我不知道这是否是你想要

public abstract class Player 
{ 
    int position; 
    DecisionMaker decisionDependency; 

    ... 

    public void TakeTurn() 
    { 
    position += RollDice(); 
    GameOption option GetOptions(position); 
    MakeDescion(option); 
    } 

    protected int RollDice() 
    { 
    //do something to get the movement 
    } 

    protected abstract void MakeDecision(GameOption option); 

} 

Public class ComputerPlayer : Player 
{ 
    public ComputerPlayer() 
    { 
    decisionDependency = new AIDecisionMaker(); 
    } 

    protected override void void MakeDecision(GameOption option) 
    { 
    decisionDependency.MakeDecision(option); 
    //do stuff, probably delgate toan AI based dependency 
    } 
} 

Public class HumanPlayer : Player 
{ 
    public HumanPlayer() 
    { 
    decisionDependency = new UIDecisionMaker(); 
    } 

    protected override void void MakeDecision(GameOption option) 
    { 
    decisionDependency.MakeDecision(option); 
    //do stuff, probably interacting with the a UI or delgate to a dependency 
    } 
} 
+1

请缩进你的代码,这很难理解。 – 2008-09-18 16:10:20

0

我说什么,该游戏类不应该关心如果这是一个电脑玩家或人类玩家。它应该始终在下一个玩家类别上拨打TakeTurn。如果这是一个人类玩家,它是类的责任,与用户沟通并要求用户该做什么。这意味着它会阻止,直到用户下定决心。由于通常UI交互发生在应用程序的主线程中,因此阻止TakeTurn不会阻止整个应用程序,否则用户输入无法处理,而游戏等待TakeTurn

2

如果游戏正在管理游戏状态做I/O,那么游戏做得太多了。

你想让游戏紧紧集中在规则,轮到和状态变化上。 游戏并不知道玩家是什么;它只知道它有玩家。

您希望玩家在轮回期间检查游戏状态并执行法律行为。

人类运动员和整个游戏共享一个共同的I/O包,显示游戏状态并提示人类的输入。

通过使游戏的I/O包为Observer,可以充分利用Java Observable。这样,游戏状态更改就会报告给I/O以进行显示或记录,或者两者兼而有之。

0

取而代之的是游戏类调​​用TakeTurn上所有球员的球员应该叫TakeTurn游戏类如果有合适的球员,走的是游戏类应验证轮到他了。

这应该有助于解决用户计算机球员的问题。

2

我可能没有两个HumanPlayerComputerPlayer类,但是一个Player类在创建时使用正确的输入策略进行配置。

玩家获得的信息来决定在游戏的下一回合的移动方式是唯一件事变化(从原来的问题描述,至少),所以只是封装在一个单独的抽象。

无论设置游戏的高级别玩家还应该创建两组玩家(一个人,另一个计算机模拟),并为每个玩家设置适当的输入策略,然后只需将这些玩家对象分配给游戏目的。游戏类将只在给定的玩家列表上调用TakeTurn方法,用于每次新的回合。

+0

+1支持合成而不是继承。 – Fuhrmanator 2012-04-18 12:49:02