策略设计模式-在带有计数器的策略之间进行选择

发布于 2024-11-19 05:24:50 字数 1474 浏览 2 评论 0原文

我正在使用 Java 进行编程,但这更多的是一个设计问题,因此任何面向对象的程序员都可以回答这个问题。我有一个关于策略设计模式的问题。以下是我发现有用的几种墨水:

  1. 策略模式解释 - OO 设计

我使用策略模式两次,一组为四个策略,一组为三个策略。在每种情况下,我都会通过维护一个衰减计数器来决定使用哪种策略。如果软件决定使用的策略成功,则计数器加一。如果所使用的策略不成功,则计数器减一。无论成功或失败,所有计数器都会乘以 0.9 左右的数字,以随着时间的推移“衰减”计数器。软件将根据哪个策略具有最高的计数器来选择使用哪个策略。我的非常简单的 UML 示例如下所示:

Example UML

并以链接形式(为了更容易阅读): UML 示例

上面的 UML 是我想使用的模型。如果你不能从上面的 UML 中看出,我正在编写一个石头、剪子、布游戏,目的是打败我所有的朋友。

现在,讨论问题:

我无法决定如何实现“计数器系统”来决定使用哪种策略。我正在考虑某种“数据”类,可以存储所有计数器和历史字符串,但这对我来说似乎很笨重。我始终维护着大约 2 个字符串和大约 8 个计数器(也许更多也许更少)。这就是为什么我正在考虑一个可以存储所有内容的“数据”类。我可以实例化要在 ChooseStrategy() 和 ChooseMetaStrategy() 方法中使用的类,但我只是不知道。这是我的第一个项目,我将独自完成,我无法决定任何事情。我觉得肯定有更好的解决方案,但我没有足够的经验来知道。

谢谢!

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

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

我正在研究 Paul Sonier 关于使用复合模式的建议,它看起来非常有趣(谢谢 Paul!)。出于历史匹配和“智能”反旋转策略的目的,我想实现两个类都可以访问的所有对手游戏的字符串。另外,我希望无论我的程序采取什么策略,都可以编辑历史字符串,以便我可以准确记录对手的比赛。字符串越全面(实际上我可能会使用 LinkedList,但如果有人知道更好的(子字符串/子列表)搜索方法/集合,请告诉我)策略可以更好地预测对手的行为。

我想知道如何在仍然使用复合模式的同时实现这个“字符串”或集合。

此外,TheCapn 提出,为每个对手存储不同的计数器和历史集合是一个好主意。关于如何使用复合模式实现这一点有什么想法吗?

I am programming in Java but this is a more of a design question so any OO programmer could probably answer this question. I have a question concerning the Strategy design pattern. Here are several inks I have found useful:

  1. Strategy Pattern Explained-OO Design.

I am using the strategy pattern twice with one group of four strategies and one group of three. In each case I am deciding which strategy to use by maintaining a decaying counter. if the strategy the software decides to use is successful then the counter is incremented by one. If the strategy used is not successful then the counter is decremented by one. Regardless of success or failure ALL counters are multiplied by a number around .9 to "decay" the counters over time. The software will choose which strategy to use based on which strategy has the highest counter. An example of my very simple UML is shown below:

Example UML.

And in Link form (for easier reading):
Example UML

The UML above is the mockup I would like to use. If you can't tell from the above UML, I am writing a Rock, Paper, Scissors game with the intention of beating all of my friends.

Now, on to the problem:

I cannot decide how to implement the "counter system" for deciding which strategy to use. I was thinking about some kind of "data" class where all counters and history strings could be stored, but that just seemed clunky to me. At all times I am maintaining about 2 strings and about eight counters (maybe more maybe less). That is why I was thinking about a "data" class where everything could be stored. I could just instantiate the class to be used in the chooseStrategy() and chooseMetaStrategy() methods, but I just don't know. This is my first project that I will be working on my own for and I just cannot decide on anything. I feel like there is definitely a better solution but I am not experienced enough to know.

Thanks!

------------------------------------follow-up 1--------------------------------------------

Thank you so very much on everyone's answers and kind words. I do have a few follow up questions though. I am new to StackOverflow (and loving it) so if this is not the correct place for a followup question please let me know. I am editing my original post because my follow-up is a little lengthy.

I was looking into Paul Sonier's advice about using the composite pattern and it looked very interesting (thanks Paul!). For the purpose of the HistoryMatching and "intelligent" AntiRotation strategies I want to implement a string of all opponent plays accessible to both classes. Also, I want the history string to be edited no matter what strategy my program played so that I can keep an accurate record of the opponent's plays. The more comprehensive the string (actually I will probably use a LinkedList but if anyone knows of a better (sub-String/sub-List) search method/collection please let me know) the better the strategy can predict the opponent's behavior.

I was wondering how I could implement this "string" or collection while still using the composite pattern.

Also, TheCapn brought up that it would be a good idea to store different counters and history collections for each opponent. Any thought on how to implement this with the composite pattern?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

情话已封尘 2024-11-26 05:24:50

理想情况下,目的是让计数器与策略相关联,因为它们正在计算策略的成功情况。然而,您不一定希望策略知道它们被计算在内的事实。对我来说,这表明了一种复合模式,即您将策略类包装在一个类中,该类具有用于跟踪/降级/修改使用计数的逻辑。

这为您提供了局部性(计数与其计数的策略一起存储)和功能组合(计数功能封装在组合类中)。此外,它还保持策略类与其他影响的隔离。

到目前为止,你的设计分解看起来不错;你肯定走在一条美好而有趣的道路上。希望这有帮助!

Ideally, the intent is to have the counters be associated with the strategies, because they're counting the successes of the strategies. However, you don't necessarily want the strategies to know anything about the fact that they're being counted. To me, this indicates a Composite pattern, whereby you wrap your Strategy class in a class which has logic for tracking / degrading / modifying the count of usages.

This gives you locality (the count is stored with the strategy it's counting) and functional composition (count functionality is encapsulated in the composition class). As well, it maintains the isolation of the strategy class from other influences.

Your design breakdown so far looks good; you're certainly on a good and interesting path. Hope this helps!

别把无礼当个性 2024-11-26 05:24:50

首先,我建议您尝试一些更简单的方法: 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);

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

但是,如果您执意要计数,那么我要做的就是创建一个 装饰器 它包装策略并保留计数,并且可以与其他此类对象进行比较。代码是最简单的解释:

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 中。将它们放在一个列表中。当您需要策略时,请仔细检查列表,调用每个策略,直到找到一个有效的策略。然后,只需 对列表进行排序。然后策略将按从最好到最差的顺序排列。

Firstly, i'd suggest you try something a bit simpler: move-to-front. Keep your strategies in a list, initially in an arbitrary order. Work through them like this:

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);

Basically, a successful strategy moves straight to the head of the queue; over time, good strategies accumulate near the head. It's not as subtle as something based on counts, but it's simple, and in practice, for all sorts of uses, it works very well.

However, if you're dead set on a count, then what i'd do is create a Decorator which wraps a strategy and keeps a count, and which can be compared with other such objects. Code is the easiest explanation:

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);
    }
}

In the main object, take your actual strategies, and wrap each in a ScoredStrategy. Put those in a list. When you need a strategy, work over the list, calling each strategy until you hit one that works. Then, simply sort the list. The strategies will then be in order, from best to worst.

听风念你 2024-11-26 05:24:50

虽然“笨重”,但我认为你的直觉是正确的。将所有数据存储在一个集合中,您选择实施的策略可以访问该集合。为每个对手保留单独的 data 对象,并在定义新对手时创建新的 data 对象,将它们存储在一个集合中,例如 Map将提供轻松的访问性。

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

围绕这个问题的唯一其他逻辑(来自我简短的头脑风暴)是更好地定义您计划实施的周围逻辑或启发法。如果您创建一种更具体的方法来选择 MetaStrategy,您将更好地了解需要如何收集数据以供访问。汤姆·安德森的方法看起来对您的项目很有希望!

Although "clunky" I think your intuition is correct. Store all data in a collection that can be accessed by the strategy you choose to implement. Keep separate data objects for each of your opponents and create new data objects when you define new opponents, storing them in a collection such as a Map will provide easy accessability.

The reason behind this is if/when you decide to change "MetaStrategies" you'll need the relevent information accessible to your objects, by storing them in other, abstract objects you may find the searching/parsing/gathering of data more difficult then it should be. This also closely matches the mental model you've generated for yourself so attempting to go against that flow will possibly lead to design mistakes.

The only other logical away around this (from my brief brainstorming) is to better define the surrounding logic or heuristics you plan to implement. If you create a more concrete way of picking a MetaStrategy you'll have a better understanding of how the data needs to be collected for access. Tom Anderson's method looks promising for your project!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文