【发布时间】:2020-10-13 15:40:50
【问题描述】:
如果我有一个类包含另一个类(通过组合),而另一个类又包含另一个类。例如:包含 PersonalDetails 类的 Teacher 类,其中包含 ContactInformation 类。
ContactInformation 类:
class ContactInformation
{
private:
std::string m_email{};
std::string m_phoneNumber{};
public:
ContactInformation(const std::string &email, const std::string &phone)
: m_email{ email }, m_phoneNumber{ phone }
{
}
// Solution 1
const std::string& getEmail() const { return m_email; }
const std::string& getPhoneNumber() const { return m_phoneNumber; }
// Solution 2
const ContactInformation& getContactInfo() const { return *this; }
// Solution 3
friend class Teacher;
};
PersonalDetails 类:
class PersonalDetails
{
private:
ContactInformation m_contact;
std::string m_name;
public:
PersonalDetails(const ContactInformation &info, const std::string &name)
: m_contact{ info }, m_name{ name }
{
}
// Solution 1
const std::string& getEmail() const { return m_contact.getEmail(); }
const std::string& getPhoneNumber() const { return m_contact.getPhoneNumber(); }
const std::string& getName() const { return m_name; }
// Solution 2
const ContactInformation& getContactInfo() const { return m_contact.getContactInfo(); }
const PersonalDetails& getPersonalDetails() const { return *this; }
// Solution 3
friend class Teacher;
};
教师班:
class Teacher
{
private:
PersonalDetails m_details;
double m_salary{};
public:
Teacher(const PersonalDetails &details, double salary)
: m_details{ details }, m_salary{ salary }
{
}
// Solution 1
const std::string& getEmail() const { return m_details.getEmail(); }
const std::string& getPhoneNumber() const { return m_details.getPhoneNumber(); }
const std::string& getName() const { return m_details.getName(); }
double getSalary() const { return m_salary; }
void printEmail1() const
{
std::cout << getEmail() << '\n';
}
// Solution 2
const ContactInformation& getContactInfo() const { return m_details.getContactInfo(); }
const PersonalDetails& getPersonalDetails() const { return m_details.getPersonalDetails(); }
void printEmail2() const
{
std::cout << getContactInfo().getEmail() << '\n';
}
// Solution 3
const std::string& getTeacherEmail(const ContactInformation &c) const
{
return c.getEmail();
}
void printEmail3() const
{
std::cout << getTeacherEmail(getContactInformation());
}
};
Teacher 类访问 ContactInformation(最“嵌套”类)中的成员(m_email 和 m_phoneNumber)的“正确方式”是什么? 我想出的解决方案都没有那么好。
解决方案 1;是为所有类中的成员变量提供getter方法。但这似乎是个坏主意,因为 Teacher 类最终会有很多 getter 方法。特别是如果我将来要添加更多课程。
解决方案 2;是返回实例本身。我不知道这是否更好,或者它是否违反了任何最佳实践。但是你可以使用 Teacher 类中的实例来调用 getEmail() 。
解决方案 3;正在使用朋友课程(没有很多使用它们的经验)。但由于您仍然必须传递一个 ContactInformation 实例才能获取 m_email。它似乎与解决方案 2 没有太大区别。
有什么方法可以让 Teacher 类成为 ContactInformation 类的朋友(或其他东西),这样我就可以做这样的事情:
teacher.getEmail();
除了 ContactInformation 中的 getter 之外,不需要任何 getter?
【问题讨论】:
-
我尽量避免使用 getter/setter 方法,而是尝试遵循“告诉,不要问”原则 (TDA) 或也称为“好莱坞原则”(不要打电话给我们,我们会叫你)——换句话说,不要让 Teacher 对象被动地保存数据,而是让它有行为。但如果 TDA 在这种情况下不起作用,我会让 Teacher getter 调用它的成员的 PersonalDetails getter,并让 PersonalDetails getter 调用其成员的 ContactInformation getter。
-
使用 getter 和 setter 与正确封装相反。与其需要传递其内部数据的数据结构,不如将它们视为交互对象。我不记得在哪次谈话中听到过这样一个伟大的比喻:当你去酒吧时,服务员不会打开你的钱包,清点你所有的钱,减去一瓶啤酒的价格,然后把差额放回你的钱包(但这就是这个 setter/getter 狂热导致
customer.setMoney( customer.getMoney() - priceForOneBeer);的地方) -
@idclev463035818 我可能应该尝试找到一些关于 TDA 的好资源,似乎它真的可以帮助我更好地构建我的程序。但是如果我要遵循“告诉,不要问”的原则,我将如何重组我的程序?在 Teacher 而不是 ContactInfo 类中使用 printEmail() 可能是一个不好的例子。但是,如果我有一个接受 ContactInformation 类型的对象的外部函数,那该怎么办呢?我是否应该尝试将该逻辑放入 ContactInfo 类中?
标签: c++ composition member-variables