公共静态常量变量是否破坏了封装意识形态

Does a public static const variable break the encapsulation ideology?

本文关键字:坏了 封装 意识形态 是否 变量 静态 常量      更新时间:2023-10-16

我似乎总是在决定一个应该staticconst的类中的值应该是公共的还是私有的,使用静态的公共方法进行访问。

class DeepThought
{
public:
    static const int TheAnswer = 42;
};

对:

class DeepThought
{
public:
    static int GetTheAnswer() { return TheAnswer; }
private:
    static const int TheAnswer = 42;
};

我想用第一种方式来做,但在我内心深处的某个地方,感觉它打破了封装,即使它是一个恒定的值。第二种方式似乎并没有真正向表格添加任何东西,并且不必要地使代码混乱。

所以我问,这两种选择有什么根本性的问题吗?如果有,那是什么?

在纯粹的理论意义上,第二种选择更正确。在实际意义上,我同意你的看法 - 用 getter 函数包装常量值是没有用的,无论如何都会被编译器删除。

根据我的经验,有时更简单的方法更好,即使它在某种程度上违反了 OOP。

最后一点 - 我们曾经为此使用枚举:

enum CONSTS
{
    TheAnswer = 42,
};
它们在

语义上并不等效。更喜欢第一个,因为它产生一个完整的常量表达式,可用于数组边界、非类型模板参数、大小写表达式等。

int a[DeepThought::TheAnswer];      // ok
int b[DeepThought::GetTheAnswer()]; // broken

你应该考虑为什么OOP"意识形态"说不要暴露变量,只暴露getter。 通常的论点是因为在将来的某个时候,您可能需要使对该变量的访问执行更复杂的操作。 但是这种情况的几率一开始就很小,当你谈论一个常数时,这种可能性会变得更小。

我会继续将常量公开为常量。 但是,我通常也会在当前不需要getter时继续公开变量。 Python团队会称之为"你不需要它"原则的应用。

很明显:

class DeepThought
{
public:
    static int GetTheAnswer() { return 42; }
};

你也可以使用第一个。考虑一下 - 你要投入什么逻辑来GetTheAnswer()?您无法在不破坏其接口注意事项的情况下更改其签名或静态事实。这意味着,除非你要开始制作非常恒定的全局变量,这将是非常糟糕™的,否则你可以放入GetTheAnswer()中,你不能放入TheAnswer分配到的constexpr中。

此外,你可以用GetTheAnswer()做什么是有限制的,例如,首先你可以获取常量的地址,而用GetTheAnswer(),你不能,即使你应该能够这样做是相当合理的。

这样的这些常量基本上是隐藏的单例模式。只有一个常量实例可用。这将是此类代码的正常演变:

class DeepThought {
public:
   static const int i=10;
   void f() { std::cout << i; }
};

然后你需要更改变量以在运行时更改,它将变成这样:

   class Singleton {
      static Singleton &get() { static Singleton s; return s; }
      int get_i() const { return i; }
   };
   class DeepThought {
   public:
     void f() { std::cout << Singleton::get().get_i(); }
   };

然后在某些时候,你会想要这个常量的多个实例,它会变成这样:

  struct Data
  {
     int i;
  };
  class DeepThought {
  public:
    DeepThought(Data &d) : d(d) { }
    void f() { std::cout << d.i; }
  private:
    Data &d;
  };
  int main() { Data d; DeepThought dt(d); dt.f(); }

在代码的演变过程中,它会发生很大的变化,如果你有大量这样的代码,那么进行更改可能需要大量的努力。