доступ к частям составного класса - PullRequest
1 голос
/ 18 мая 2011

Я как-то запутался с понятием композиции и инкапсуляции.

Вот пример, который помогает моему узкому месту: У меня есть класс A, в котором есть части типов B и C. В B есть также части типов D и E.

class A
{
   B itsB;
   C itsC;
}

class B
{
   D itsD;
   E itsE;
}

class D
{
   int mAlpha;
   int getAlpha();
   void setAplha(int);
}

A itsA;

В этом случае, как вам доступ только для чтения mAlpha?

Сюда? itsA->getItsB()->getItsD()->getAlpha()

или так? itsA->getAlpha(), где A::getAlpha() доступ itsB->getItsD()->getAlpha()

А как насчет способа записи доступа mAlpha?

Сюда? itsA->getItsB()->getItsD()->setAlpha(10.0)

или так? itsA->getItsB()->setAlpha(10.0), где A::getAlpha() доступ itsB->getItsD()->setAlpha(10.0)

Итак, вопрос в том; чтобы получить доступ / изменить части составного класса, следуя принципу инкапсуляции, следует ли вам получать доступ только через интерфейс составного класса?

В противном случае кажется, что вы получаете доступ к детали, изменяете ее без ведома / разрешения владельца композиции.

Пожалуйста, помогите мне избавиться от этой путаницы

Спасибо.

Ответы [ 4 ]

0 голосов
/ 18 мая 2011

Я воспринимаю «инкапсуляцию» как общую концепцию. Класс имеет несколько полей, свойств, методов, которые рассматриваются как один элемент, независимо от того, являются ли эти члены общедоступными, частными или защищенными. Для «инкапсуляции» не имеет значения, есть ли у объекта другие объекты или нет как члены.

class CarClass {
  private: double InitialPrice;
  protected: WheelClass wheels[4];
  protected: MotorClass motor;
  public: turnOn();
  public: turnOff();
}

Здесь "инкапсуляция" означает, давайте возьмем эти поля, будем ли использовать простые типы данных или объекты, эти методы и поместим их все вместе в сущность.

Для «составного класса» или «составного объекта» я воспринимаю его как объект, в состав которого входят другие объекты. Класс или объект отвечают за создание или уничтожение этих подэлементных объектов. Если у класса есть указатели или ссылки на другие объекты, но он не отвечает за их удаление или добавление (размещение в памяти), то он не является составным.

class SpaceShipClass {

  SpaceShipClass() {
   this.engine = new EngineClass();
   this.wings  = new WingClass();
  } 

  ~SpaceShipClass() {
   free this.engine();
   free this.wings();
  } 

  private: EngineClass engine; 
  protected: WingsClass wings; 
  public: PilotClass pilot; 

  public: Fly(); 
  public: Landing(); 
}

В предыдущем примере «engine» и «wings» делают «SpaceShipClass» составным классом. Но поле «пилот» - не потому, что оно «не принадлежит» классу, оно просто имеет ссылку.

Убедитесь, что я не использую область члена класса (приватную, защищенную или общедоступную) как нечто связанное с понятиями «инкапсуляция» или «композиция», он является частью O.O.P., но он не нужен для инкапсуляции или композиции. На самом деле есть О.О. Языки программирования, в которых все члены являются открытыми и могут иметь классы инкапсуляции или композиции.

Языки программирования со «ссылками» затрудняют начинающим понимать «композицию классов».

0 голосов
/ 18 мая 2011

Я бы позволил A делегировать доступ к getAlpha(), выставив себе те же имя метода и сигнатуру.

class A
{
public:
    int getAlpha()
    {
        return itsB.getAlpha();
    }
};

class B
{
public:
    int getAlpha()
    {
        return itsD.getAlpha();
    }
};

Хотя это усложняет ваш код, вам следует подумать об изменении способа инкапсуляции обязанностей.

0 голосов
/ 18 мая 2011

В этом случае как вам доступ только для чтения к mAlpha?

Сюда? itsA-> getItsB () -> getItsD () -> getAlpha ()

или так? itsA-> getAlpha (), где A :: getAlpha () обращается к itsB-> getItsD () -> getAlpha ()

Это немного сложно, так как вы должны соблюдать оба уровня инкапсуляции. Предположительно, B используется как дополнение к реализации A, так что вы можете захотеть, чтобы B был частным членом A, исключая возможность первого метода. Второй способ скрывает существование B внутри A и позволяет из некоторых контрактов быть реализованными в A относительно того, что он будет позволять делать с его B. Вы могли бы размещать то же самое между B и D, где вы этого не делаете. просто подайте указатель на D и возьмите альфа-представление, но используйте D для реализации в частном порядке. В итоге вы получите слои методов, вызывающих друг друга, и в простых случаях это кажется неэффективным, но это о том, что клиент A знает о своей реализации и о том, что клиент B знает о реализации B.

С этой точки зрения ваша первая строка написана так, чтобы потребитель A знал внутреннюю структуру, чтобы добраться до значения Alpha. Он должен знать, что там есть B с буквой D, у которой есть альфа. Чтобы учесть изменения в реализации A, вы бы скрыли эту деталь за функцией, такой как getAlpha (). Тогда то же самое для Б.

НТН

-Крис

0 голосов
/ 18 мая 2011

Итак, вопрос в том; чтобы получить доступ / изменить части составного класса, следуя принципу инкапсуляции, следует ли вам получать доступ только через интерфейс составного класса?

Согласно принципу инкапсуляции, детали композита должны быть скрыты. Предполагая, что mAlpha логически является свойством A, но реализовано в D, вы должны добавить методы доступа в A, которые ищут / изменяют mAlpha член в своей D части. В противном случае вы могли бы просочиться в детали реализации A (что это составная часть D и некоторых других вещей).

...