37

我第一次做一个大项目。我有很多类,其中一些具有公共变量,一些具有带有 setter 和 getter 方法的私有变量,并且同样具有两种类型。

我决定重写这段代码,主要只使用一种类型。但我不知道我应该使用哪个(仅用于同一对象中的方法的变量始终是私有的,不是这个问题的主题)。

我知道公共和私人意味着什么的理论,但在现实世界中使用的是什么,为什么?

4

7 回答 7

40

private数据成员通常被认为是好的,因为它们提供了封装。

为它们提供 getter 和 setter 打破了这种封装,但它仍然比public数据成员更好,因为只有一次访问该数据的点。

您会在调试过程中注意到这一点。如果它是私有的,你知道你只能修改类内部的变量。如果它是公开的,您将不得不搜索整个代码库以查找可能被修改的位置。

尽可能禁止 getter/setter 和 make properties private。这遵循了信息隐藏的原则——你不应该关心一个类有什么属性。它应该是独立的。当然,在实践中这是不可行的,如果可行,那么遵循这一点的设计将比不遵循这一点的设计更加混乱和难以维护。

这当然是一个经验法则——例如,我只使用 a struct(相当于具有class公共访问权限的 a ),比如说,一个简单的点类:

struct Point2D
{
   double x;
   double y;
};
于 2013-01-18T13:28:16.167 回答
19

既然您说您知道理论,并且其他答案已经深入探讨了公共/私有、getter 和 setter 的含义,我想专注于为什么使用访问器而不是创建公共属性(C++ 中的成员数据) .

假设您在物流项目中有一个卡车类:

class Truck {
public:
    double capacity;

    // lots of more things...
};

如果您是北美人,您可能会使用加仑来表示卡车的容量。想象一下,您的项目已经完成,它运行良好,尽管Truck::capacity已经完成了许多直接使用。实际上,您的项目取得了成功,因此一些欧洲公司要求您调整您的项目以适应他们;不幸的是,该项目现在应该使用公制系统,因此应该使用升而不是加仑来表示容量。

现在,这可能是一团糟。当然,一种可能性是只为北美准备一个代码库,只为欧洲准备一个代码库。但这意味着应该在两个不同的代码源中应用错误修复,这被认为是不可行的。

解决方案是在您的项目中创建配置可能性。用户应该能够设置加仑或升,而不是固定的、硬连线的加仑选择。

使用上面看到的方法,这将意味着大量工作,您将必须跟踪 的所有用途Truck::capacity,并决定如何处理它们。这可能意味着修改整个代码库中的文件。作为替代方案,让我们假设您决定采用更多theoretic方法。

class Truck {
public:
    double getCapacity() const
        { return capacity; }

    // lots of more things...
private:
    double capacity;
};

一个可能的替代更改不涉及对类接口的修改:

class Truck {
public:
    double getCapacity() const
        { if ( Configuration::Measure == Gallons ) {
            return capacity;
          } else {
             return ( capacity * 3.78 );
          }
        }


    // lots of more things...
private:
    double capacity;
};

(请注意,有很多方法可以做到这一点,一种只是一种可能性,这只是一个例子)

您必须创建全局实用程序类配置(但无论如何您都必须这样做),并在truck.hfor中添加一个包含configuration.h,但这些都是本地更改,您的代码库的其余部分保持不变,从而避免了潜在的错误。

最后,你还说你现在在一个大项目中工作,我认为这些原因实际上更有意义。请记住,在大型项目中工作时要牢记的目标是创建可维护的代码,即您可以更正并使用新功能扩展的代码。您可以忘记个人小型项目中的 getter 和 setter,尽管我会尽量让自己习惯它们。

希望这可以帮助。

于 2013-01-18T13:51:52.533 回答
12

对于什么应该是私有的/公共的或受保护的,没有硬性规定。

这取决于您的班级的角色及其提供的内容。

  • 构成类内部工作的所有方法和成员都应设为私有
  • 一个班级向外界提供的一切都应该是公开的。
  • 可能必须在此类的特化中扩展的成员和方法可以声明为protected
于 2013-01-18T13:50:08.020 回答
4

从 OOP 的角度来看,getter/setter 有助于封装,因此应始终使用。当您调用 getter/setter 时,该类可以在幕后为所欲为,并且该类的内部不会暴露在外部。

另一方面,从 C++ 的角度来看,如果类在您只想获取/设置一个值时做了很多意想不到的事情,这也可能是一个劣势。人们想知道某些访问是否会导致巨大的开销或是否简单高效。当您访问公共变量时,您确切地知道您得到了什么,当您使用 getter/setter 时,您不知道。

尤其是如果你只做一个小项目,花时间编写 getter/setter 并在你决定更改变量名称/类型/时相应地调整它们会产生大量的忙碌工作而收效甚微。你最好把时间花在编写有用的代码上。

当 C++ 代码不提供真正的收益时,它们通常不使用 getter/setter。如果您设计一个 1,000,000 行的项目,其中包含许多必须尽可能独立的模块,这可能是有道理的,但对于您每天编写的大多数正常大小的代码来说,它们是多余的。

于 2013-01-18T14:08:00.997 回答
3

有一些数据类型的唯一目的是保存明确指定的数据。这些通常可以编写为具有公共数据成员的结构。除此之外,一个类应该定义一个抽象。公共变量或琐碎的 setter 和 getter 表明设计没有经过充分考虑,导致聚集了一些没有抽象任何东西的弱抽象。与其考虑数据,不如考虑行为:这个类应该做 X、Y 和 Z。从那里,决定需要哪些内部数据来支持所需的行为。一开始这并不容易,但要不断提醒自己重要的是行为,而不是数据。

于 2013-01-18T14:00:28.803 回答
1

通常不鼓励使用公共变量,更好的形式是将所有变量设为私有并使用 getter 和 setter 访问它们:

private int var;

public int getVar() {
  return var;
}

public void setVar(int _var) {
  var = _var;
}

Eclipse 等现代 IDE 提供“实现 Getter 和 Setter”和“封装字段”等功能(用相应的 getter 和 setter 调用替换所有对变量的直接访问),从而帮助您做到这一点。

于 2013-01-18T13:29:04.243 回答
1

私有成员变量优于公共成员变量,主要是出于上述原因(封装、明确指定的数据等)。它们还提供了一些数据保护,因为它保证没有外部实体可以在需要时通过 setter 的正确通道来更改成员变量。

getter 和 setter 的另一个好处是,如果您使用的是 IDE(如 Eclipse 或 Netbeans),则可以使用 IDE 的功能来搜索代码库中调用该函数的每个位置。它们提供了关于该特定类中的一条数据在何处被使用或修改的可见性。此外,您可以通过使用内部互斥锁轻松地使对成员变量的访问成为线程安全的。getter/setter 函数将在访问或修改变量之前获取此互斥锁。

我支持抽象到它仍然有用的程度。为了抽象而抽象通常会导致比它的价值更复杂的混乱。

于 2013-01-18T16:36:08.883 回答