C++ 如何在不影响战略模式的情况下使其可维护?

C++ 如何在不影响战略模式的情况下使其可维护?,c++,strategy-pattern,C++,Strategy Pattern,我正在努力设计一个满足我所有要求的设计 我有一套算法,可以单独执行,也可以在各种配置中组合以产生额外的输出 这些算法可能代价高昂,如果只运行一次,则应将结果兑现以供以后使用 这些算法可以在不同的环境中使用 这些算法应该可以扩展,这样它们就能够跟上每年的标准修订 设计应该是可维护的 我满足这些要求的第一次尝试是在以下设计中使用策略模式  行为计算的输出缓存在行为本身中 这满足要求1、2、3,但不满足要求4 调用CalculateOutput()需要30个不同的参数,这些参数是它自己的,以及允许它

我正在努力设计一个满足我所有要求的设计

我有一套算法,可以单独执行,也可以在各种配置中组合以产生额外的输出

  • 这些算法可能代价高昂,如果只运行一次,则应将结果兑现以供以后使用

  • 这些算法可以在不同的环境中使用

  • 这些算法应该可以扩展,这样它们就能够跟上每年的标准修订

  • 设计应该是可维护的

  • 我满足这些要求的第一次尝试是在以下设计中使用策略模式

    行为计算的输出缓存在行为本身中

    这满足要求1、2、3,但不满足要求4

    调用CalculateOutput()需要30个不同的参数,这些参数是它自己的,以及允许它调用其他具体行为所必需的参数。对一个函数的参数进行更改将产生连锁反应,通常会导致所有行为必须更新其参数列表

    此外,缓存系统无法正常工作,因为行为之间并不总是存在1:1的映射。例如,要从EnergyBehaviour生成输出,它需要执行多个调用NHSolarPosition。“NHSolarPosition”如何仅为单个缓存的“输出”缓存多个“偶然角度”

    我试图解决上述问题,将所有参数封装在它们自己的类型“PVPanel”中,并将其传递给行为。这是有问题的,原因有二。首先,对简单行为的调用有很大的开销,因为可能只需要几个参数,但是还有许多其他参数没有被使用或相关。其次,将“PVPanel”类型传递到行为中导致需求2失败,我无法在PVPanel之外的上下文中使用行为


    我正在努力将我的所有需求协调到一个单一、优雅的设计中。

    我不确定您的行为类是否表示函数及其参数,以及您是否使用一个行为实例并为不同的调用更新其属性。您仍然可以在您的行为中缓存多个调用,但可能更简单的方法是将缓存从这里移除,并将其作为这些系统的用户的责任

    我应该补充一点,如果在给定系统状态的情况下,输出计算总是得到相同的结果,那么您只需要缓存。如果模型中存在不同的状态,那么对于这些行为之一的相同输出,您能否得到不同的结果

    对您的问题的评论建议使用参数的
    std::map
    。另一个选项是为计算提供特定的参数类。查看访问者模式或
    std::variant
    ,了解如何包装这些特定参数类型


    std::map
    可能更容易,因为它可以解决您使用
    PVPanel
    和需求2的问题。这只是从
    PVPanel
    实例或任何其他类型填充
    std::map
    的一种情况。或者,您可以将
    PVPanel
    类型上的访问器向上移动到
    PVPanel
    和其他未来类型实现的界面中。

    您能否将示例场景进一步缩减为抽象且易于理解的场景?我读了三遍你的文章,但我仍然不知道什么是特别的,什么是共同的。这让我困惑,一切都取决于一切,你所有的类型都是某种特殊的,但应该使用一些通用的。。。对不起,听起来有点复杂。。。也许这就像您希望传递一个可以包含任何参数的通用数据结构,而不是单独或在自定义类中传递硬编码参数。作为一个简单的例子,您可以命令您的每个算法将一个
    std::map
    作为其输入,并返回一个不同的
    std::map
    作为其输出。然后取决于每个算法,它希望在输入映射中看到哪些键/值对,以及它将在输出映射中放置哪些键/值对。(当然,你还是想记录下期望的参数,这样算法就可以互操作)我同意并投票支持@JeremyFriesner评论。我的两分钱是,缓存等需求在很多时候都可以被视为大局中的单个组件(例如,类CalculationMemoryCache),并且在构建系统时不会给您的头脑带来混乱。例如,如果输入和输出都是抽象的,那么您可以使用各种缓存机制,并检查是否已经执行了对给定输入的任何调用,并且是否缓存了该调用,从而允许您仅从缓存中获取输出,而无需重新执行该输入的计算。