防止破坏封装

时间:2014-12-30 14:51:00

标签: c++ encapsulation 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() {};
    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;
    };

这是一个更好的设计(因为我没有获得实际的私人价值)?

3 个答案:

答案 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)

封装允许仅通过类中的方法控制属性。这两个例子都是封装的。