Рефакторинг кода — получение инкапсуляции Пример кодирования DELPHI Рефакторинг кода — это способ получить хорошую структуру. С помощью рефакторинга мы можем улучшить качество кода и увеличить степень повторного использования кода, сохраняя при этом функции неизменными. Вот конкретный пример того, как улучшить качество кода и добиться инкапсуляции. (В примере используется DELPHI) Функция кода: установка фильтра для набора данных (TClientDataSet). Пользователь может выбрать поле для фильтрации в TComboBox, а затем ввести значение для фильтрации в поле Tedit. Как показано на рисунке 1: наиболее распространенный метод — жестко запрограммировать имена полей в нашем наборе данных в атрибуте Items TComboBox, а затем добавить в код множество операторов case или if для определения полей, выбранных пользователем. чтобы установить фильтры для набора данных устройства. ...... случай ComboBox1.ItemIndex of0: ClientDataSet.Filtered := False; ClientDataSet.Filter := ' F_CODE = ''' + Edit2.Text + ''''; ClientDataSet.Filtered := True;1: ClientDataSet .Filtered := False; ClientDataSet.Filter := ' F_CHINESE_NAME = ''' + Edit2.Text + ''''; ClientDataSet.Filtered := True;... end; Или используйте... if ComboBox1.Text = 'Код материала', затем start ClientDataSet.Filtered := False; ClientDataSet.Filter := ' F_CODE = ''' + Edit2.Text + ''''; ClientDataSet.Filtered := True; endelse, если ComboBox1.Text = 'name', затем начать ClientDataSet.Filtered := False; ClientDataSet.Filter := ' F_CHINESE_NAME = ''' + Edit2.Text + ''''; ClientDataSet.Filtered := True;end... Этот код также реализует настройку фильтров для набора данных посредством жесткого кодирования. отвечает потребностям, но приведенный выше код негибок. Если в наборе данных много полей, кодировщику необходимо вводить поля по одному в Items, а порядок необходимо проверять при написании дела. В противном случае фильтр набора будет неправильным, и разработчикам будет легко его внедрить. ОШИБКА. Также неудобно поддерживать большое количество операторов if при использовании if, и это не поддерживает изменения по требованию. Когда пользователь запрашивает изменение отображаемого имени поля набора данных на китайском языке, он также должен не забыть изменить жестко закодированные данные. в TComboBox Items. Если вы забудете, появится ОШИБКА. Итак, в первой реконструкции я пытался динамически загружать данные в TComboBox Items, и в то же время, чтобы добиться сравнения при выборе пользователем после загрузки. Я добавил частное поле FFields: array[0..20, 0..2] string; в эту ФОРМУ запроса, чтобы сохранить данные информации о поле в наборе данных. При этом реализуется процесс загрузки данных: PROcedure TFrmSPARealStorageQuery.GetQueryFields;var i, iFieldsCount: Integer;begin iFieldsCount := 0; с DBGride1.DataSource.DataSet do start for i := 0 to Fields.Count - 1 сделать, если Fields[ i].Visible, затем начать FFields[iFieldsCount, 0] := Fields[i].FieldName; FFields[iFieldsCount, 1] := Fields[i].DisplayLabel; Inc(iFieldsCount); end; ComboBox1.Items.Clear; for i := 0 to iFieldsCount - 1 do ComboBox1.Items.Add; (FFields[i, 1]); end;end; Это обеспечивает динамическую загрузку информации о полях во время выполнения. Итак, мои настройки фильтра выглядят так. if ComboBox1.Text <> '' thenbeginClientDataSet.Filtered := False; ClientDataSet.Filter := FFields[ComboBox1.ItemIndex, 0] + '''' + Edit2.Text + ''''; end; этот метод, несомненно, повышает гибкость кода и повышает возможность повторного использования кода, поскольку код хорошо изолирован от изменяющихся данных. Таким образом, можно сказать, что это удобно, если вы добавляете частное поле FFields: array[0..20, 0..2] строки в другую форму, которая также хочет реализовать эту функцию, и используете описанный выше процесс динамического загрузка полей набора данных достигается повторное использование. Но такое повторное использование не очень хорошо, поскольку мы не добились хорошей инкапсуляции. Это приводит к дублированию кода, разбросанного повсюду в вашей программе (вы часто используете COPY, чтобы добиться повторного использования этой функции, поскольку приведенный выше код не имеет хорошей инкапсуляции). Если однажды вы захотите изменить функцию загрузки данных, вам придется найти место, где можно скопировать эту функцию, и вам придется изменить код, разбросанный в других местах. Поэтому я снова провел его рефакторинг и дополнительно инкапсулировал код. Код следующий: unit uDataSetFieldsInfo; // Описание: Модуль включает класс TDataSetFieldsInfo, который инкапсулирует получение информации о подсегментах набора данных. // И предоставляет интерфейс метода для отображения информации в поле отображения списка со списком и получения соответствующего имени подраздела // Создано: wuchhao // Дата: 2003.5interfaceuses Classes, DBClient, StdCtrls;type TDataSetFieldsInfo = class Private FFieldsList: TStrings public конструктор; Создать ; деструктор Уничтожить; процедура GetDataSetFields(Источник: TClientDataSet); процедура ShowFieldsInfo (Target: TComboBox); функция GetFieldsNameByDisplayLabel (DisplayLabel: string): строка; конец; реализация { TDataSetFieldsInfo } конструктор TDataSetFieldsInfo.Create; начало FFieldsList := TStringList.Create; конец; деструктор TDataSetFieldsInfo.Destroy;begin FFieldsList.Free; inherited;end;procedure TDataSetFieldsInfo.GetDataSetFields(Source: TClientDataSet);var i: Integer;begin FFieldsList.Clear; with Source do start for i := 0 to Fields.Count - 1 do if Поля[i].Visible, затем начинаются FFieldsList.Add(Fields[i].DisplayLabel); FFieldsList.Add(Fields[i].FieldName); конец; конец;конец;функция TDataSetFieldsInfo.GetFieldsNameByDisplayLabel(DisplayLabel: строка): строка;индекс var: целое число;начало Результат: = ''; индекс: = FFieldsList.IndexOf(DisplayLabel); <> -1 then Result := FFieldsList.Strings[index+1] ;end;procedure TDataSetFieldsInfo.ShowFieldsInfo(Target: TComboBox);var i: Integer;begin Target.Items.Clear; while i < FFieldsList; .Count do start Target.Items.Add(FFieldsList.Strings[i]); i:= i+ 2; end;end;end. Модуль uDataSetFieldsInfo инкапсулирует данные и методы, связанные с реализацией функций, описанных в этой статье, и инкапсулирует их в класс, тем самым реализуя принцип открытия-закрытия в объектно-ориентированном проектировании. Класс становится черным ящиком, поэтому его можно легко использовать повторно (повторное использование черного ящика), не беспокоясь о дублировании кода. В то же время, поскольку он инкапсулирует информацию, связанную с функциями, обязанности класса четко определены (единая ответственность), а также он имеет достаточную степень детализации и хорошую инкапсуляцию. TdataSetFieldsInfo эффективно изолирует поле со списком от изменения данных, что в конечном итоге повышает степень повторного использования кода, одновременно уменьшая обязанности класса FORM и количество жестко запрограммированных магических чисел. Вот новый код: Сначала объявите ссылку на класс TdataSetFieldsInfo в форме. ...Вызов при создании FORM: FFieldsInfo := TDataSetFieldsInfo.Create;FFieldsInfo.GetDataSetFields(cdMaster);FFieldsInfo.ShowFieldsInfo(ComboBox1); В это время мои настройки фильтра становятся следующими: if ComboBox1.Text <> '' thenbeginClientDataSet.Filtered := Ложь; ClientDataSet.Filter := FFieldsInfo.GetFieldsNameByDisplayLabel(ComboBox1.Text) + '''' + Edit2.Text + ''''; ClientDataSet.Filtered := True;end; Получить соответствующий подраздел, вызвав процедуру интерфейса объекта FfieldsInfo имя. Эта статья представляет собой простой пример рефакторинга кода. Я думаю, что класс, который я реализовал выше, можно написать разными способами и использовать лучшие алгоритмы. Это просто для того, чтобы дать представление о рефакторинге кода. Чтобы улучшить качество нашего кода, его удобство обслуживания и масштабируемость, мы рассмотрим идеи метода программирования OOD.