Главная - Литература

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 [44] 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294

почтового индекса, номера телефона или ставки зарплаты (job classification), нет логической связи. Методы, предоставляющие доступ к деталям SQL-запросов, относятся к гораздо более низкому уровню абстракции, чем класс Employee, нарушая общую абстракцию класса.

Не включайте в класс открытые члены, плохо согласующиеся с абстракцией интерфейса Добавляя новый метод в интерфейс класса, всегда спрашивайте себя: «Согласуется ли этот метод с абстракцией, формируемой существующим интерфейсом?» Если нет, найдите другой способ внесения изменения, позволяющий сохранить согласованность абстракции.

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

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

Хорошая инкапсуляция

Как я уже говорил в разделе 5.3, инкапсуляция является бо-

лее строгой концепцией, чем абстракция. Абстракция по- р

могает управлять сложностью, предоставляя модели, позво- сулируйте детали рваяшайи»»

ляющие игнорировать детали реализации. Инкапсуляция не радала ЬХ

позволяет узнать детали реализации, даже если вы этого

захотите.

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

Минимизируйте доступность классов и их членов Ми-

Самым важным отяичй«м хоро-

нимизация доступности - одно из нескольких правил, под- оирштирошдао мда»

держивающих инкапсуляцию. Если вы не можете понять, от плохо слроектрованного яа-

каким делать конкретный метод: открытым, закрытым или ляатся степень, в которой мо-

защищенным, - некоторые авторы советуют выбирать са- скрывает сш внутренние

мый строгий уровень защиты, который работает (Meyers, Л***** другие детали реали-

.глг. Т.Г 1 А.ч к J эамии от других модулей.

1998; Bloch, 2001). По-моему, это прекрасное правило, но

г. Лжошуа Вш Uoshm Bfoch)

мне кажется, что еще важнее спросить себя: «Какой вари- j \ /

ант лучше всего сохраняет целостность абстракции интерфейса?» Если предоставление доступа к методу согласуется с абстракцией, сделайте его открытым. Если вы не уверены, скрыть больше обычно предпочтительнее, чем скрыть меньше.

Не делайте данные-члены открытыми Предоставление доступа к данным-членам нарушает инкапсуляцию и ограничивает контроль над абстракцией. Как



указывает Артур Риэль, класс Point (точка), который предоставляет доступ к данным:

float х; float у; float z;

нарушает инкапсуляцию, потому что клиентский код может свободно делать с данными Point что угодно, при этом сам класс может даже не узнать об их изменении (Riel, 1996). В то же время класс Point, включающий члены:

float GetXO; float GetYO float GetZO void SetX( float x ) void SetY( float у ) void SetZ( float z )

поддерживает прекрасную инкапсуляцию. Вы не имеете понятия о том, реализованы ли данные как float х,у и z, хранит ли класс Point эти элементы как double, преобразуя их в float, или же он хранит их на Луне и получает через спутник.

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

Пример обнародования деталей реализации класса (С++)

class Employee { public:

Employee(

FullName name, String address, String workPhone, String homePhone, Taxld taxIdNumber, JobClassification jobClass

FullName GetNameO const; String GetAddressO const;

private:

I- Обнародованные детали реализации.

->[" String m Name;

String m Address; int mJobClass;



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

Общий способ решения этой проблемы описал Скотт Мейерс в разделе 34 книги «Effective С++, 2d ed» (Meyers, 1998). Отделите интерфейс класса от его реализации, после чего включите в объявление класса указатель на его реализацию, но не включайте других деталей реализации.

Пример сокрытия деталей реализации класса (С++)

class Employee { public:

Employee( ... );

FullName GetNameO const; String GetAclclress() const;

private:

- Детали реализации скрыты при помощи указателя.

Employeelmplementation *m implementation; };

Теперь вы можете поместить детали реализации в класс Employeelmplementation, который будет доступен только классу Employee, но не использующему этот класс коду

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

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

-- инициализируйте х, у и z значением 1.0, потому что

-- при инициализации значением 0.0 DerivedClass не работает

Избегайте использования дружественных классов Иногда - например, при реализации шаблона Состояние (State) - дисциплинированное использование дружественных классов помогает управлять сложностью (Gamma et al., 1995). Однако обычно дружественные классы нарушают инкапсуляцию. Они увеличивают объем кода, о котором приходится думать в каждый конкретный момент времени, повышая тем самым сложность программы.



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 [44] 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294



0.0104