2011-07-07 120 views
10

我使用Java编程,但这是一个更多的设计问题,所以任何OO程序员都可能回答这个问题。我有一个关于战略设计模式的问题。这里有几个油墨我发现有用:策略设计模式 - 在计数器策略之间进行选择

  • Strategy Pattern Explained-OO Design
  • 我正在使用战略模式两次,一组四个策略和一组三个。在每种情况下,我都通过维护一个衰减计数器来决定使用哪种策略。如果软件决定使用的策略成功,则计数器增加1。如果使用的策略不成功,则计数器减1。无论成功或失败,所有计数器都会乘以一个大约.9的数字,以随着时间的推移“衰减”计数器。软件将根据哪种策略具有最高计数器来选择使用哪种策略。我非常简单的UML的一个例子如下所示:

    Example UML

    而且在链接的形式(为便于阅读): Example UML

    上面的UML是我想用的样机。如果你不能从上面的UML中得知,我正在写一个Rock,Paper,Scissors游戏,目的是要打败我所有的朋友。

    现在,这个问题:

    我不能决定如何实施“反制”确定使用哪种策略。我正在考虑一些可以存储所有计数器和历史字符串的“数据”类,但对我来说这似乎很笨拙。在任何时候,我都保持着大约2个弦乐器和大约8个计数器(可能更多也许更少)。这就是为什么我在考虑可以存储所有内容的“数据”类。我可以实例化要在chooseStrategy()中使用的类并选择MetaStrategy()方法,但我只是不知道。这是我第一个为自己工作的项目,我无法决定任何事情。我觉得肯定有更好的解决方案,但我没有足够的经验知道。

    谢谢!

    ------------------------------------后续1 -------- --------------------------------------

    非常感谢大家的回答和善的话。不过,我确实有一些跟进问题。我是StackOverflow的新手(并且很喜欢它),所以如果这不是跟进问题的正确位置,请告诉我。我正在编辑我的原始文章,因为我的后续工作有点冗长。

    我正在研究Paul Sonier关于使用复合模式的建议,它看起来很有趣(感谢Paul!)。为了HistoryMatching和“智能”AntiRotation策略的目的,我希望实现一系列对两个类都可访问的对手游戏。另外,无论我的程序播放什么策略,我都希望编辑历史字符串,以便我能够保持对对手戏剧的准确记录。字符串越全面(实际上我可能会使用LinkedList,但如果有人知道更好的(子字符串/子列表)搜索方法/集合,请让我知道),策略可以更好地预测对手的行为。

    我想知道如何实现这个“字符串”或集合,同时仍然使用复合模式。另外,TheCapn提出,为每个对手存储不同的计数器和历史集合是一个不错的主意。任何关于如何用复合模式实现这个想法?

    +3

    考虑到你的第一个项目,真的很感谢你的思维方向,并且你明白一个好设计的重要性 –

    回答

    5

    理想情况下,其目的是让计数器与策略相关联,因为它们计数策略的成功。然而,你不一定希望这些策略知道他们被计数的事实。对我来说,这表示一个复合模式,您可以将您的策略​​类包装在具有跟踪/降级/修改用法计数逻辑的类中。

    这为您提供了地点(计数与其计数策略一起存储)和功能组合(计数功能封装在组合类中)。同样,它保持战略类别与其他影响的隔离。

    您的设计故障迄今看起来不错;你当然是在一条好的和有趣的道路上。希望这可以帮助!

    +0

    嘿!感谢你的回答,它确实有帮助。我确实编辑了我的帖子,但还有几个问题,所以如果你有机会看看他们,我会非常感激。再次感谢! –

    2

    首先,我建议你尝试一下更简单:move-to-front。将你的策略放在一个列表中,最初以任意的顺序。通过他们这样的工作:

    List<Strategy> strategies; 
    Strategy successfulStrategy = null; 
    for (Strategy strategy: strategies) { 
        boolean success = strategy.attempt(); 
        if (success) { 
         break; 
         successfulStrategy = strategy; 
        } 
    } 
    if (successfulStrategy == null) throw new NoSuccessfulStrategyException(); 
    // now move the successful strategy to the front of the list 
    strategies.remove(successfulStrategy); 
    strategies.add(0, successfulStrategy); 
    

    基本上,一个成功的策略,直接移动到队列的头;随着时间的推移,良好的策略积累在头顶附近。它不像基于计数的东西那么微妙,但它很简单,并且在实践中,对于各种用途,它工作得很好。

    但是,如果你死了一个计数,那么我会做的就是创建一个Decorator,它包装一个策略并保持一个计数,并且可以与其他这样的对象进行比较。代码是最简单的解释:

    public class ScoredStrategy implements Strategy, Comparable<ScoredStrategy> { 
        private final Strategy delegate; 
        private float score; 
    
        public ScoredStrategy(Strategy delegate) { 
         this.delegate = delegate; 
        } 
    
        public boolean attempt() { 
         boolean success = delegate.attempt(); 
         score = (score * 0.9f) + (success ? 1 : -1); 
         return success; 
        } 
    
        public int compareTo(ScoredStrategy that) { 
         return -Float.compare(this.score, that.score); 
        } 
    } 
    

    在主要对象,采取实际的策略,并在ScoredStrategy包装每个。把这些列入清单。当你需要一个策略,在列表上工作,调用每个策略,直到你找到一个可行的策略。然后,只需sort the list。这些策略将按顺序排列,从最好到最差。

    +1

    我认为你想在你的for循环中完成任务后打破它。 – Lii

    1

    虽然“笨重”,我认为你的直觉是正确的。将所有data存储在collection中,可以通过您选择实施的策略进行访问。当你定义新的对手时,为你的每个对手保留单独的data对象,并创建新的data对象,将它们存储在诸如Map之类的集合中将提供易于访问的功能。

    这个背后的原因是,如果/当您决定更改“MetaStrategies”时,您需要可以访问您的对象的相关信息,将它们存储在其他抽象对象中,您可能会发现搜索/解析/收集数据应该是更困难的。这也与您为自己生成的心智模型紧密匹配,因此试图违背该流程可能会导致设计错误。

    围绕这个(从我简短的头脑风暴中)唯一的另一个逻辑是更好地定义你计划实现的周围逻辑或启发式。如果你创建一个更具体的选择MetaStrategy的方法,你将更好地理解如何收集数据以进行访问。汤姆安德森的方法看起来很有希望为您的项目!

    +0

    这是你提出的关于跟踪不同对手的不同数据集的优秀点。直到你提起这件事之前,我一直没有想过。谢谢! –