Книга Чистая архитектура. Искусство разработки программного обеспечения, страница 10. Автор книги Роберт Сесил Мартин

Разделитель для чтения книг в онлайн библиотеке

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

Cтраница 10
Заключение

Именно эта возможность создавать программные единицы, неправильность которых можно доказать, является главной ценностью структурного программирования. Именно поэтому современные языки обычно не поддерживают неограниченное применение инструкций goto. Кроме того, именно поэтому функциональная декомпозиция считается одним из лучших приемов на архитектурном уровне.

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

Именно эти ограничения мы будем подробно изучать в последующих главах.

Глава 5. Объектно- ориентированное программирование
Чистая архитектура. Искусство разработки программного обеспечения

Как мы увидим далее, для создания хорошей архитектуры необходимо понимать и уметь применять принципы объектно-ориентированного программирования (ОО). Но что такое ОО?

Один из возможных ответов на этот вопрос: «комбинация данных и функций». Однако, несмотря на частое цитирование, этот ответ нельзя признать точным, потому что он предполагает, что o.f() — это нечто отличное от f(o). Это абсурд. Программисты передавали структуры в функции задолго до 1966 года, когда Даль и Нюгор перенесли кадр стека функции в динамическую память и изобрели ОО.

Другой распространенный ответ: «способ моделирования реального мира». Это слишком уклончивый ответ. Что в действительности означает «моделирование реального мира» и почему нам может понадобиться такое моделирование? Возможно, эта фраза подразумевает, что ОО делает программное обеспечение проще для понимания, потому что оно становится ближе к реальному миру, но и такое объяснение слишком размыто и уклончиво. Оно не отвечает на вопрос, что же такое ОО.

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

Давайте исследуем эти понятия по очереди.

Инкапсуляция?

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

Эта идея определенно не уникальная для ОО. Например, в языке C имеется превосходная поддержка инкапсуляции. Рассмотрим простую программу на C:


point.h

struct Point;

struct Point* makePoint(double x, double y);

double distance (struct Point *p1, struct Point *p2);


point.c

#include "point.h"

#include

#include


struct Point {

  double x,y;

};


struct Point* makepoint(double x, double y) {

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

  p->x = x;

  p->y = y;

  return p;

}


double distance(struct Point* p1, struct Point* p2) {

  double dx = p1->x - p2->x;

  double dy = p1->y - p2->y;

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

}

Пользователи point.h не имеют доступа к членам структуры Point. Они могут вызывать функции makePoint() и distance(), но не имеют никакого представления о реализации структуры Point и функций для работы с ней.

Это отличный пример поддержки инкапсуляции не в объектно-ориентированном языке. Программисты на C постоянно использовали подобные приемы. Мы можем объявить структуры данных и функции в заголовочных файлах и реализовать их в файлах реализации. И наши пользователи никогда не получат доступа к элементам в этих файлах реализации.

Но затем пришел объектно-ориентированный C++ и превосходная инкапсуляция в C оказалась разрушенной.

По техническим причинам [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


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 инкапсуляция была частично восстановлена. Однако это был лишь грубый прием (хак), обусловленный технической необходимостью компилятора видеть все переменные-члены в заголовочном файле.

Вход
Поиск по сайту
Ищем:
Календарь
Навигация