god对象的总体配置对象和后期初始化

Overall configuration object for a god object and late initialisation

本文关键字:对象 初始化 god 配置      更新时间:2023-10-16

这个问题有两个主要部分:将配置值存储在单个文件/位置和延迟所包含对象的初始化。

存储配置值

我有一个嵌入式程序,用于控制半自动测试的PCB测试夹具。我想把所有的极限/测试参数存储在一个地方(最好是只读/常量),这样以后就可以很容易地定位和调整它们。问题是,有些值在嵌套结构中,我所知道的初始化这些对象的唯一方法是使用可怕的初始化器列表,在该列表中,所有可追溯性都丢失了(或者使用了一个几乎同样糟糕的构造函数)。

例如

class Configuration {
public:
  struct NestedStruct {
    float value1;
    float value2;
    float value3;
  };
  struct ContainerStruct {
    int value1;
    float value2;
    NestedStruct nested1;
    NestedStruct nested2;
    NestedStruct nested3;
    float value3;
  };
  // Initialise struct data member.
  // Not obvious which value is which?
  constexpr static const ContainerStruct containerStruct {5, 2.3, 1.4, 4.2, 0.7, 3.5, 2.5, 3.5, 0.2, 0.2, 0.1, 4.6};
  // Slightly more readable
  constexpr static const ContainerStruct containerStruct {5, 2.3, {1.4, 4.2, 0.7}, {3.5, 2.5, 3.5}, {0.2, 0.2, 0.1}, 4.6};
};

如何在保持可读性的同时,将由复杂/嵌套结构值组成的只读配置值存储在一个位置?

控制器/上帝对象初始化

我决定将核心功能封装到一个单独的控制器对象中,该对象实例化多个包含的对象。其中一个对象通过指针传递给其他一些对象。我使用上面提到的配置值(有很多!)来初始化这些对象。

使用initializer列表会使Controller类的构造函数又长又乱。我可以绕过这一点的一种方法是为包含的对象创建一个空的构造函数,并使用一个单独的initializer函数,我可以在Controller的构造函数的主体中调用该函数。

然而,我一直读到两步/延迟初始化是不好的,因为对象不能立即使用。还有别的办法吗?

也许还有比把它包在神的物体里更好的方法吗?

我想存储在一个地方的示例参数:

Adc对象参数:

float voltageReference;
uint8_t slaveSelectPin;

NavigationButtons对象参数:

struct AdcValues {
  uint_fast16_t buttonUp;
  uint_fast16_t buttonDown;
  uint_fast16_t buttonLeft;
  uint_fast16_t buttonRight;
  uint_fast16_t buttonCentre;
  uint_fast8_t tolerance;
};

UutPower对象参数:

struct CurrentCompensation {
  float LowX;
  float LowC;
  float MidX;
  float MidC;
  float HighX;
  float HighC;
};

电压测试对象参数:

struct TestParameter {
  float scalingFactor; // Potential divider scaling for voltages >voltageRef.
  float limitLower;
  float limitUpper;
  const char *signalName;
};
// Lots of nested structs.
struct TestParameters {
  TestParameter tb1_1;
  TestParameter tp15;
  TestParameter tp4;
  TestParameter tp1;
  TestParameter tp3;
  TestParameter tp20;
  TestParameter tp12;
  TestParameter tp29;
  TestParameter tp28;
  TestParameter con3_6;
  TestParameter con3_2;
}

其他参数:

float currentLimitLow;
float currentLimitHigh;
const char *version; 

感谢您的帮助。

最可行的选择可能是将结构拆分为单独的const变量,您必须通过变量命名或其他方式对它们进行分组。

一旦有了这个,就可以更改链接器文件,为每个变量提供一个专用地址。或者,编译器可能有一个非标准的扩展,比如@运算符。

这允许您单独初始化每个这样的变量。

这对于维护来说非常好,因为添加或删除变量不会更改其他不相关变量的地址。仔细规划你的记忆地图,在这里和那里留下"洞",以便将来扩展。如果适用的话,考虑对齐(如果你使用一些8位垃圾MCU,这不会是一个问题)。

这样做的另一个优点是,可以将const变量本地化到使用它们的文件中,而不是将它们保留在全局"怪物结构"中。