C ++: интерфейс композиции - PullRequest
2 голосов
/ 04 января 2010

Так что я потратил некоторое время на размышления об этом и всюду по Google искал «решение» (решение, скорее всего, является вопросом предпочтения, но я не уверен в этом). Ниже приведена проблема, с которой я столкнулся, но эту проблему можно применить ко многим ситуациям, связанным с композицией.

У меня есть класс Color, содержащий элементы красного, зеленого, синего и альфа. Каждый из них имеет функцию set и get. Достаточно просто.

class Colour
{
    public:
        float getRed();
        void setRed(float);
        float getGreen();
        void setGreen(float);
        ...
    private:
        float red;
        float green;
        ...
};

Я буду использовать этот класс в других классах для определения их цвета, например (для краткости опускаем конструктор и деструктор):

class ColourableObject
{
    private:
        Colour colour;
};

Теперь моя проблема заключается в следующем: как классу ColourableObject лучше всего получить доступ к этому объекту Color? Было бы лучше получить объект Color для прямого доступа к его функциям-членам, например:

class ColourableObject
{
    public:
        Colour& getColour();
    private:
        Colour colour;
};

Или было бы лучше дать классу ColourableObject свой собственный набор и получить функции для цвета, в которых действуют на объект Color, например, так:

class ColourableObject
{
    public:
        float getRed();
        void setRed(float);
        ...
    private:
        Colour colour;
};

Для меня первый вариант наиболее логичен, поскольку он избавил бы от множества проблем при добавлении функциональности в каждый класс, для которого требуется этот объект Color, просто воздействуя непосредственно на этот объект Color.

Однако не является ли последний более восприимчивым к изменениям в классе ColourableObject? Не говоря уже о том, что colourableObject.getColour (). SetRed (x) не кажется мне слишком естественным, так как get и set конфликтуют друг с другом.

У меня, вероятно, совершенно неправильный подход. Я относительно новичок в C ++, поэтому я готов учиться! Таким образом, вопрос заключается в том, должен ли я использовать первый метод, второй метод или совершенно другой метод?

Ответы [ 6 ]

3 голосов
/ 04 января 2010

Не для того, чтобы прямо ответить на ваш вопрос, но я бы избавился от всех сеттеров (обычно это плохой признак, чтобы иметь сеттеры в любом случае) и использовал бы конструктор:

Color c = Color( 123, 17, 77 );

где три параметра конструктора являются значениями RGB.

1 голос
/ 29 марта 2012

В конечном счете, ответ зависит от того, как вы хотите (или не хотите) ограничить доступ к встроенному объекту Color.

На ваш первый выбор ...

class ColourableObject
{
public:
    Colour& getColour();
private:
    Colour colour;
};

... вы действительно вообще не ограничиваете доступ. Если пользователь может получить доступ к приватному участнику через getColour(), какой смысл делать его приватным? Вы можете также пропустить промежуточный шаг и просто сделать это:

class ColourableObject
{
public:
    Colour colour;
};

Делая это таким образом, человек может просто обратиться непосредственно к элементу данных и ко всем его функциям, таким как C.colour.getRed(); (при условии, что C является ColourableObject)

Теперь, скажем, вы хотите каким-то образом ограничить конечного пользователя - он не может установить зеленый или синий, но вы позволите ему установить красный. В этом случае вы можете использовать второй вариант:

class ColourableObject
{
public:
    float getRed();
    void setRed(float);
    ...
private:
    Colour colour;
};

Это потому, что пользователь ColourableObject будет иметь доступ только к вашим общедоступным функциям, а не к базовому частному члену. Это обоснование также справедливо, если вы хотите иметь промежуточный шаг между конечным пользователем и выбором цвета. Например, следующее:

class ColourableObject
{
public:
    void setMood(enum Mood);
private:
    Colour colour;
};

void ColourableObject::setMood(enum Mood)
{
   if(Mood == HAPPY) colour.setRed(3);
   if(Mood == SAD)  colour.setBlue(11);
   ...
}

Наконец, вы могли бы создать гибрид, который бы поддерживал общедоступность элемента данных colour, но также добавлял дополнительные элементы доступа к этому элементу данных.

Резюме:

  • Первый метод:

    • Pro's: Интерфейс для Цвета проходит через.
    • Con's: делает элемент данных общедоступным.
  • Второй метод:

    • Pro's: инкапсулирует данные. Будущие изменения в интерфейсе Colour только нарушат ваш код, а не конечного пользователя.
    • Con: вы должны заново реализовать любую часть интерфейса Colour, которую вы хотите, чтобы конечный пользователь мог использовать.
1 голос
/ 04 января 2010

Принцип DRY поддерживает ваш первый вариант, предоставляя доступ к объекту Colour.

Кроме того, вы можете изменить

    Colour& getColour();

до

    const Colour& getColour();
    void setColour( const Colour& );

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

1 голос
/ 04 января 2010

В этом случае использование геттеров и сеттеров не имеет большого смысла. С таким же успехом можно обнародовать float членов Colour. Если вам не требуется проверка или манипулирование более чем одним закрытым членом, просто сделайте это публичным и создайте конструктор для инициализации Colour соответственно.

Что касается ColourableObject, вопрос, который вы должны задать, будет: нужны ли другим, не связанным классам доступ к члену Colour объекта? Нужно ли будет вносить в него изменения? Если ответом на или из них будет «нет», я бы сказал, что у вас вообще не должно быть никакого метода получения или установки этого объекта. В противном случае, опять же, если вам не требуется проверка или дополнительные изменения состояния, просто сделайте Colour общедоступным.

1 голос
/ 04 января 2010

Я, вероятно, воссоздаю ваш класс в случае, если вам понадобится добавить другие цвета, такие как оранжевый, фиолетовый, голубой или новый Smooky Applewood от Crayola!

Вроде как базовый цветовой класс, и действуйте в соответствии с этим базовым классом, вводя новый цвет. Таким образом, не имеет значения, с каким цветом вы имеете дело. Это все черный ящик. Кроме того, это ответит на ваш второй вопрос, поскольку не имеет значения, какого это цвета, вам не нужно переопределять методы имен setColor и getColor. Им не нужно знать или заботиться о том, какого цвета вы говорите.

Я думаю, что в Code Complete (в книге) есть раздел, который немного раздражает при просмотре классов, в которых слишком много методов get / set. Обычно это сводится к неправильному способу ведения дел.

0 голосов
/ 05 января 2010

Лично я предпочел бы отбросить часть "get", в случае члена Colorable:

colorableObject.Color().setRed(1.0f);

Это, как вы сказали, полностью личное предпочтение (как и написание! :), но для меня это выглядит как «свойство», а не как метод получения / установки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...