Чтение онлайн

на главную - закладки

Жанры

Чистая архитектура. Искусство разработки программного обеспечения
Шрифт:

 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);

12

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

 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] .

13

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

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

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

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

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

14

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

Взгляните на дополнение к нашей исходной программе 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 = name;

 return p;

}

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

 np->name = name;

}

char* getName(struct NamedPoint* np) {

 return np->name;

}

main.c

#include "point.h"

#include "namedPoint.h"

#include <stdio.h>

int main(int ac, char** av) {

 struct NamedPoint* origin = makeNamedPoint(0.0, 0.0, "origin");

 struct NamedPoint* upperRight = makeNamedPoint

 (1.0, 1.0, "upperRight");

 printf("distance=%f\n",

 distance(

 (struct Point*) origin,

 (struct Point*) upperRight));

}

Внимательно рассмотрев основной код в файле

main.c
, можно заметить, что структура данных
NamedPoint
используется, как если бы она была производной от структуры
Point
. Такое оказалось возможным потому, что первые два поля в
NamedPoint
совпадают с полями в
Point
. Проще говоря,
NamedPoint
может маскироваться под
Point
, потому что
NamedPoint
фактически является надмножеством
Point
и имеет члены, соответствующие структуре
Point
, следующие в том же порядке.

Поделиться:
Популярные книги

Школа. Первый пояс

Игнатов Михаил Павлович
2. Путь
Фантастика:
фэнтези
7.67
рейтинг книги
Школа. Первый пояс

Лейб-хирург

Дроздов Анатолий Федорович
2. Зауряд-врач
Фантастика:
альтернативная история
7.34
рейтинг книги
Лейб-хирург

Не грози Дубровскому! Том VIII

Панарин Антон
8. РОС: Не грози Дубровскому!
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Не грози Дубровскому! Том VIII

Вернуть невесту. Ловушка для попаданки

Ардова Алиса
1. Вернуть невесту
Любовные романы:
любовно-фантастические романы
8.49
рейтинг книги
Вернуть невесту. Ловушка для попаданки

Идеальный мир для Лекаря

Сапфир Олег
1. Лекарь
Фантастика:
фэнтези
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря

Последний Паладин. Том 4

Саваровский Роман
4. Путь Паладина
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Последний Паладин. Том 4

Титан империи 7

Артемов Александр Александрович
7. Титан Империи
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Титан империи 7

На руинах Мальрока

Каменистый Артем
2. Девятый
Фантастика:
боевая фантастика
9.02
рейтинг книги
На руинах Мальрока

Сопряжение 9

Астахов Евгений Евгеньевич
9. Сопряжение
Фантастика:
боевая фантастика
постапокалипсис
технофэнтези
рпг
5.00
рейтинг книги
Сопряжение 9

Здравствуй, 1985-й

Иванов Дмитрий
2. Девяностые
Фантастика:
альтернативная история
5.25
рейтинг книги
Здравствуй, 1985-й

Генерал-адмирал. Тетралогия

Злотников Роман Валерьевич
Генерал-адмирал
Фантастика:
альтернативная история
8.71
рейтинг книги
Генерал-адмирал. Тетралогия

Машенька и опер Медведев

Рам Янка
1. Накосячившие опера
Любовные романы:
современные любовные романы
6.40
рейтинг книги
Машенька и опер Медведев

Беглец. Второй пояс

Игнатов Михаил Павлович
8. Путь
Фантастика:
фэнтези
героическая фантастика
боевая фантастика
5.67
рейтинг книги
Беглец. Второй пояс

Защитник. Второй пояс

Игнатов Михаил Павлович
10. Путь
Фантастика:
фэнтези
5.25
рейтинг книги
Защитник. Второй пояс