Чистая архитектура. Искусство разработки программного обеспечения. Роберт Мартин
Чтение книги онлайн.

Читать онлайн книгу Чистая архитектура. Искусство разработки программного обеспечения - Роберт Мартин страница 14

СКАЧАТЬ техническим причинам[12] компилятор C++ требует определять переменные-члены класса в заголовочном файле. В результате объектно-ориентированная версия предыдущей программы Point приобретает такой вид:

      point.h

      class Point {

      public:

       Point(double x, double y);

       double distance(const Point& p) const;

      private:

       double x;

       double y;

      };

      point.cc

      #include "point.h"

      #include <math.h>

      Point::Point(double x, double y)

      : x(x), y(y)

      {}

      double Point::distance(const Point& p) const {

       double dx = x-p.x;

       double dy = y-p.y;

       return sqrt(dx*dx + dy*dy);

      }

      Теперь пользователи заголовочного файла point.h знают о переменных-членах x и y! Компилятор не позволит обратиться к ним непосредственно, но клиент все равно знает об их существовании. Например, если имена этих членов изменятся, файл point.cc придется скомпилировать заново! Инкапсуляция оказалась разрушенной.

      Введением в язык ключевых слов public, private и protected инкапсуляция была частично восстановлена. Однако это был лишь грубый прием (хак), обусловленный технической необходимостью компилятора видеть все переменные-члены в заголовочном файле.

      Языки Java и C# полностью отменили деление на заголовок/реализацию, ослабив инкапсуляцию еще больше. В этих языках невозможно разделить объявление и определение класса.

      По описанным причинам трудно согласиться, что ОО зависит от строгой инкапсуляции. В действительности многие языки ОО практически не имеют принудительной инкапсуляции[13].

      ОО безусловно полагается на поведение программистов – что они не станут использовать обходные приемы для работы с инкапсулированными данными. То есть языки, заявляющие о поддержке OO, фактически ослабили превосходную инкапсуляцию, некогда существовавшую в C.

      Наследование?

      Языки ОО не улучшили инкапсуляцию, зато они дали нам наследование.

      Точнее – ее разновидность. По сути, наследование – это всего лишь повторное объявление группы переменных и функций в ограниченной области видимости. Нечто похожее программисты на C проделывали вручную задолго до появления языков ОО[14].

      Взгляните на дополнение к нашей исходной программе point.h на языке C:

      namedPoint.h

      struct NamedPoint;

      struct NamedPoint* makeNamedPoint(double x, double y, char* name);

      void setName(struct NamedPoint* np, char* name);

      char* getName(struct NamedPoint* np);

      namedPoint.c

      #include "namedPoint.h"

      #include <stdlib.h>

      struct NamedPoint {

       double x,y;

       char* name;

      };

      struct NamedPoint* makeNamedPoint(double x, double y, char* name) {

       struct NamedPoint* p = malloc(sizeof(struct NamedPoint));

       p->x = x;

       p->y = y;

       p->name СКАЧАТЬ



<p>12</p>

Чтобы иметь возможность определить размер экземпляра каждого класса.

<p>13</p>

Например, Smalltalk, Python, JavaScript, Lua и Ruby.

<p>14</p>

И не только программисты на C: большинство языков той эпохи позволяли маскировать одни структуры данных под другие.