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

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

напечатать метку поля, напечатать значение флажка.

вариант: ( битовое поле ) прочитать битовое поле, напечатать метку поля, напечатать битовое поле. Конец Выбора Конец цикла Пока

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

Этот метод также иллюстрирует наиболее сложный способ реализации табличного поиска, так как использует оператор case. Другой подход - создание абстрактного KJi2icc2iAbstractField и последующее наследование от него подклассов для каждого типа поля. Тогда вам не понадобится оператор case, вы сможете вызывать метод-член соответствующего объектного типа.

Вот как можно создать такие объекты на С++: Пример создания объектных типов (С++)

class AbstractField { public:

virtual void ReadAndPrint( string, FileStatus & ) = 0;

class FloatingPointField : public AbstractField { public:

virtual void ReadAndPrint( string, FileStatus & ) {

class IntegerField ... class StringField ...

Этот фрагмент объявляет во всех классах метод, принимающий строковый параметр и параметр типа FileStatus.

Следующий шаг - объявление массива для хранения набора объектов. Этот массив и есть таблица для поиска. Вот как она выглядит:

Пример создания таблицы для хранения объектов каждого типа (С++)

AbstractField* field[ Field Last ];

Последний шаг в настройке таблицы объектов - заполнение массива Field конкретными объектами:



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

field[ Field FloatingPoint ] - new FloatingPointField(); field[ Field Integer ] = new IntegerField(); field[ Field String ] = new StringField(); field[ Field TimeOfDay ] = new TimeOfDayField(); field[ Field Boolean ] = new BooleanField(); field[ Field BitField ] = new BitFieldField();

В этом коде предполагается, что FloatingPointField и другие идентификаторы с правой стороны выражений присваивания - это имена объектов, унаследованных от AbstractField. Присваивание объектов элементам массива означает, что вы сможете вызвать правильную версию метода ReadAndPrintQ, обращаясь к элементу массива, а не используя конкретный тип объекта напрямую.

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

Пример выбора объектов и их методов из таблицы (С++)

Это строки - служебный код, необходимый для обработки каждого поля в сообщении.

"fieldldx = 1;

while ( ( fieldldx <= numFieldsInMessage ) and ( fileStatus == OK ) ) { fieldType = fieldDescription[ fieldldx J.FieldType; fieldName = fieldDescription[ fieldldx ].FieldName;

- Это - обращение к таблице, в результате которого будет вызван метод, зависящий от типа поля: он просто выбирается в таблице объектов.

-> field[ fieldType ].ReadAndPrint( fieldName, fileStatus ); }

Помните первоначальные 34 строки псевдокода табличного поиска, содержащего оператор case? Если вы замените оператор case таблицей объектов, то это весь код, который вам нужен для обеспечения той же функциональности. Невероятно, но это также весь код, необходимый для замены всех 20 отдельных методов, применяемых при логическом подходе. Более того, если описания сообщений читаются из файла, то новые типы сообщений не потребуют изменений кода, если только не будут содержать новых типов полей.

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

Сам факт, что проект использует наследование и полиморфизм, не делает его хорошим проектом. Механический объектно-ориентированный дизайн, описанный в разделе «Объектно-ориентированный подход», потребовал бы такого же большого объема кода, как и механический функциональный дизайн, а может, и больше. Такой подход скорее усложнил бы решение, чем упростил. В данном случае основная суть проектного решения не в объектной и не в функциональной ориентации, а в использовании хорошо продуманной таблицы поиска.



Подгонка значений ключа

Во всех трех предыдущих примерах вы могли использовать данные в качестве ключа для прямого обращения к таблице. То есть можно было указать переменную messagelD как ключ без всяких изменений, переменную month в примере количества дней в месяцах, а также gender, maritalStatus и smokingStatus в примере ставок страхования.

Было бы хорошо всегда обращаться к таблице напрямую, потому что это просто и быстро. Однако не всегда данные для этого годятся. В примере со ставками страхования переменная age не очень удобна в качестве ключа. Первоначальная логика определяла одну ставку для лиц моложе 18 лет, индивидуальные ставки для возрастов от 18 до 65 и одну ставку для людей старше 65. Это означает, что для возрастов от О до 17 и от 66 и выше нельзя использовать возраст как ключ напрямую, если таблица хранит только один набор ставок для нескольких лет.

Это приводит к обсуждению вопроса подгонки значений ключа в таблице поиска. Подогнать ключ можно несколькими способами.

Продублировать информацию, чтобы использовать ключ напрямую

Один прямолинейный способ заставить age работать ключом в таблице ставок - продублировать все ставки для лиц, моложе 18, для каждого возраста от О до 17, а затем использовать возраст для прямого обращения к таблице. То же самое можно сделать и для возрастов от 66 лет и старше. Преимущество этого подхода в том, что структура таблицы остается простой и доступ к данным так же прост. Если нужно добавить специальное значение ставки для некоторого возраста, меньшего 17, вы можете просто изменить табличное значение. Недостаток этого метода в том, что дублирование приведет к напрасным затратам на хранение избыточной информации, а также увеличит вероятность появления ошибок в таблице хотя бы потому, что таблица будет содержать избыточные данные.

Преобразовать ключ, чтобы использовать его напрямую Второй способ задействовать 4ge в качестве прямого ключа - применить к переменной 4ge некоторую функцию, которая позволит это делать. В данном случае такая функция должна преобразовывать все возрасты от О до 17 к какому-то одному значению, скажем, 17, а возрасты старше 66 - к другому, например, 66. В данном случае такое преобразование легко выполнить с помощью функций minQ и maxQ- Так, для создания табличного ключа в диапазоне от 17 до 66 можно использовать выражение:

тах( min( 66, Age ), 17 )

Реализация функции трансформации требует хорошего понимания структуры данных, которые вы хотите применить как ключ, и это не всегда так просто, как использование функций minQ и maxQ- Допустим, в этом примере ставки меняются через интервалы не в 5 лет, а в 1 год. Если только вы не хотите дублировать все данные по пять раз, вам придется написать функцию, которая делит Age на 5 и использует методы min() и maxQ-

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



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