Стоит ли делать объекты-члены композиции общедоступными?

У меня есть класс верхнего уровня, который создает экземпляры подмодулей, используя композицию. Пользователь знает, что в высшем классе будут эти подмодули. Стоит ли делать объекты подмодуля публичными членами, чтобы пользователь мог напрямую вызывать их функции?

Альтернатива, по-видимому, заключается в том, чтобы обернуть их вызовы функций, которые защищают подмодули от обнародования, но не имеют никаких преимуществ инкапсуляции, поскольку пользователю все равно нужно указать подмодуль.

Перед вами дом класса высший уровень с подмодульной кухней и санузлом.

// Public member objects
class Kitchen {
public:
    void turn_on_tap();
    int compute_area();
};
class Bathroom {
public:
    void turn_on_tap();
    int compute_area();
};
class House {
public:
    Kitchen kitchen;
    Bathroom bathroom;
    int compute_area() { return kitchen.compute_area() + bathroom.compute_area(); }
};

//User code:
House house;
house.kitchen.turn_on_tap();
house.bathroom.turn_on_tap();
house.compute_area() // OK
house.bathroom.compute_area(); // may not want user to be able to do this

// Private member objects
class House {
    Kitchen kitchen;
    Bathroom bathroom;
public:
    void turn_on_kitchen_tap() { kitchen.turn_on_tap(); }
    void turn_on_bathroom_tap() { bathroom.turn_on_tap(); }
    int compute_area() { return kitchen.compute_area() + bathroom.compute_area(); }
};

//User code:
House house;
house.turn_on_kitchen_tap();
house.turn_on_bathroom_tap();
house.compute_area();

Я предпочитаю синтаксис первого, но это означает, что объекты-члены должны быть общедоступными.

Второй подход кажется утомительным из-за дополнительных функций, которые мне приходится писать для переноса базовых вызовов функций. И я теряю красивое точечное иерархическое разыменование, потому что пользователь знает (и должен знать) о лежащей в основе иерархии.

РЕДАКТИРОВАТЬ: Но если я сделаю их общедоступными, я открою доступ к другим публичным функциям на кухне и в ванной, о которых я не обязательно хочу, чтобы пользователь знал. Так что тогда мне, возможно, придется сделать их приватными и использовать «друг», что становится немного уродливым.

В приведенный выше код добавлена ​​функция calculate_area().


person coderoo    schedule 17.02.2019    source источник
comment
Если в подклассах нет членов, которые могли бы изменить свое внутреннее состояние, кроме как с помощью общедоступных методов, то не должно быть проблем с наличием объекта в содержащем классе в качестве общедоступных объектов.   -  person Francis Cugler    schedule 17.02.2019


Ответы (1)


Это зависит. Если дом представляет собой простую совокупность, т.е.:

  1. Допустимое значение House — это любая комбинация допустимых значений Kitchen и Bathroom. Другими словами, нет House конкретного инварианта, который нужно было бы сохранить.

  2. Отдельные компоненты правильно обрабатывают свои собственные инварианты сами по себе и, как расширение, заданную точку № 1 контейнера.

  3. Функции-члены контейнера представляют собой просто крошечные оболочки вокруг каждого компонента или даже просто возвращают ссылку на компонент для модификации.

Тогда да, простой struct (для общего доступа по умолчанию) действительно подходит. «Инкапсуляция» здесь — просто упражнение в многословии. Иногда объект, который вам нужен, это просто набор вещей, склеенных вместе, без дополнительной логики.

Так что, хорошая это идея или нет, вам нужно будет проверить для своего собственного приложения самостоятельно.

person StoryTeller - Unslander Monica    schedule 17.02.2019