我有这堂课:
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公开了对象的内部实现。
但我怎么能阻止这个?
因为通常在我的代码中,我需要知道来自我的对象的一些私人数据(比较是一个例子),这就是我使用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;
};
这是一个更好的设计(因为我没有获得实际的私人价值)?
答案 0 :(得分:1)
第一个,即使有吸气剂,也是封装的。考虑color()
方法,它返回一个字符串。即使您更改Phone
的实现,使得您将颜色存储为枚举而不是字符串,如果您先进行某种转换,您的方法仍然可以返回字符串。重要的是,您可以在不需要更改类的用户的情况下更改color()
和底层存储的实现。
与将颜色存储为可公开访问的字符串的类进行比较。如果稍后将数据成员更改为枚举,则需要修改使用该颜色的每个位置。这不是封装的属性,而是将接口与实现分离的属性。
答案 1 :(得分:1)
正如您可能从其他答案和评论中看到的那样,答案是:这取决于。
实际上,它主要取决于使用您的类的用例。让我们先来看问题中给出的例子,对象的比较。由于我们想要比较两个电话对象或仅仅是一个特定的数据成员,从问题中看不清楚,我将在这里讨论这两种情况。
将数据成员与课外数据进行比较
让我们在这个用例中搜索重量大于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"规则,它基本上说先查询对象的状态,做出决定然后告诉对象该做什么是一个糟糕的设计。相反,我们应该只告诉对象我们想要什么,并让它为我们工作。在这个用例中这是显而易见的,因为只有在引脚正确时解锁电话才是电话的责任,而不是使用电话类的用户的责任。但是在更复杂的情况下,许多程序员将完全按照我在此描述的那样做。
回到问题:这里的一个好方法是例如
class Phone
{
private:
int pin;
bool unlocked;
public:
void CheckPin(int enteredPin) {
if (pin == enteredPin)
unlocked = true;
}
};
代码
phone.CheckPin(enteredPin);
希望这会有所帮助,并感谢@KonradRudolph指出“告诉,不要问规则”。请随时帮助我改进答案:)
答案 2 :(得分:0)
封装允许仅通过类中的方法控制属性。这两个例子都是封装的。