我有这门课:
class Phone {
private:
string producer, color;
int weight, dimension;
public:
Phone(string &producer, string &color, int &weight, int &dimension):
producer(producer), color(color), weight(weight), dimension(dimension) {};
Phone():
producer(""), color(""), weight(0), dimension(0) {};
virtual ~Phone() {};
string getProducer(void) const;
string getColor(void) const;
int getWeight(void) const;
int getDimension(void) const;
virtual void displayInfo(void) const;
};
问题出在这里是因为我通过getter暴露了对象的内部实现。
但是我该如何防止呢?
因为通常在我的代码中,我需要知道我的对象的一些私有(private)数据(比较是一个例子),这就是我使用 getter 的原因。
然后我将类重写为如下内容:
class Phone {
private:
string producer, color;
int weight, dimension;
public:
Phone(string &producer, string &color, int &weight, int &dimension):
producer(producer), color(color), weight(weight), dimension(dimension) {};
Phone():
producer(""), color(""), weight(0), dimension(0) {};
virtual ~Phone() {};
bool isTheProducer(string& producer) const { return this->producer == producer };
bool hasWeight(int& weight) const { return this->weight == weight };
bool hasDimension(int& dimension) const { return this->dimension == dimension };
virtual void displayInfo(void) const;
};
这是更好的设计吗(因为我没有得到实际的私有(private)值(value))?
最佳答案
正如您可能从其他答案和评论中看到的那样,答案是:视情况而定。
其实主要看你的类在什么用例中使用。让我们首先坚持问题中给出的例子,即对象的比较。由于从问题中无法清楚地看出我们是想比较两个电话对象还是只是一个特定的数据成员,所以我将在这里讨论这两种情况。
将数据成员与类外数据进行比较
让我们以这个用例为例,我们搜索所有权重大于 x 的手机(只是伪代码):
for (Phone& p in phoneList) {
if (p.getWeight() > x) {
cout << "Found";
}
}
然后第一个类的例子就完全没问题了,因为这不是电话的固有特征,因此电话类不负责处理它。此外,结果不会公开超出任务绝对需要的内容。
比较两个手机对象
在这种情况下,两个代码示例同样好(或者在这种情况下同样糟糕)。在这两种情况下,用户都必须了解有关电话如何表示的大量详细信息才能比较所有必要的成员。如果在以后的修订版中将新成员添加到类中,则必须调整每个比较两个电话的代码段。为了克服这个问题,可以向类中添加一个函数来准确地进行比较。
class Phone {
private:
string producer, color;
int weight, dimension;
public:
bool IsEqualTo(const Phone& other)
{
return (producer == other.producer && color == other.color &&....);
}
非比较用例
但让我们来看一个更高级的示例。让我们假设以下任务:用户将密码输入手机,如果密码正确,手机应该解锁。让我们假设一个非常天真的方法:
class Phone
{
private:
int pin;
bool unlocked;
public:
int getPin() { return pin; }
void unlock() { unlocked = true; }
};
和相应的调用
if (phone.getPin() == enteredPin)
phone.unlock();
在这种情况下,我们的情况完全不同。这里我们需要考虑 "tell, don't ask"规则,基本上是说首先查询对象的状态、做出决定然后告诉对象做什么是一个糟糕的设计。相反,我们应该只告诉对象我们想要什么,让它为我们完成工作。在此用例中,这是显而易见的,因为仅当 PIN 码正确时才解锁手机是手机的责任,而不是使用手机类的用户的责任。但在更复杂的情况下,许多程序员会完全按照我在此处描述的方式进行操作。
回到问题:一个好的解决方案是例如
class Phone
{
private:
int pin;
bool unlocked;
public:
void CheckPin(int enteredPin) {
if (pin == enteredPin)
unlocked = true;
}
};
代码
phone.CheckPin(enteredPin);
希望这会有所帮助,并感谢@KonradRudolph 指出“告诉,不要询问规则”。随时帮助我改进每个评论的答案:)
关于c++ - 防止破坏封装,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27707545/