Refactorización de código: obtención de encapsulación Ejemplo de codificación DELPHI La refactorización de código es una forma de obtener una buena estructura. A través de la refactorización, podemos mejorar la calidad del código y aumentar el grado de reutilización del código manteniendo las funciones sin cambios. A continuación se muestra un ejemplo concreto de cómo mejorar la calidad del código y obtener encapsulación. (El ejemplo usa DELPHI) Función de código: Establecer un filtro para el conjunto de datos (TClientDataSet). El usuario puede seleccionar el campo a filtrar en un TComboBox y luego ingresar el valor a filtrar en un cuadro Tedit. Como se muestra en la Figura 1: El método más común es codificar los nombres de los campos en nuestro conjunto de datos en el atributo Elementos de TComboBox y luego agregar muchas declaraciones caso o if al código para determinar los campos seleccionados por el usuario. para establecer filtros para el conjunto de datos. ...... caso ComboBox1.ItemIndex de0: ClientDataSet.Filtered := False ClientDataSet.Filter := ' F_CODE = ''' + Edit2.Text + ''''; .Filtrado := Falso; ClientDataSet.Filter := ' F_CHINESE_NAME = ''' + Edit2.Text + ''''; ClientDataSet.Filtered := True;... fin; O use... si ComboBox1.Text = 'Código de material' entonces comience ClientDataSet.Filtered := False ClientDataSet.Filter := ' F_CODE = ''' + Edit2.Text + ''''; ClientDataSet.Filtered := Verdadero; también si ComboBox1.Text = 'nombre' entonces comienza ClientDataSet.Filtered := False; ClientDataSet.Filter := ' F_CHINESE_NAME = ''' + Edit2.Text + ''''; ClientDataSet.Filtered := True;end... Este código también implementa filtros de configuración para el conjunto de datos mediante codificación rígida. Satisface las necesidades, pero el código anterior es inflexible. Si el conjunto de datos tiene muchos campos, el codificador debe ingresar los campos uno por uno en Elementos y se debe verificar el orden al escribir el caso. De lo contrario, el filtro establecido será incorrecto y será fácil para los desarrolladores introducirlo. BICHO. También es doloroso mantener una gran cantidad de declaraciones if cuando se usan declaraciones if, y no admite cambios de demanda. Cuando el usuario solicita cambiar el nombre para mostrar en chino del campo del conjunto de datos, también debe recordar cambiar el nombre duro. datos codificados en TComboBox. Si lo olvida, se introducirá un error. Entonces, en la primera reconstrucción, intenté cargar dinámicamente los datos en TComboBox Items y, al mismo tiempo, lograr una comparación cuando el usuario selecciona después de la carga. Agregué un FFields privado: matriz [0..20, 0..2] de campo de cadena; a este FORMULARIO de consulta para guardar los datos de información del campo en el conjunto de datos. Al mismo tiempo, se implementa un proceso de carga de datos: PRocedure TFrmSPARealStorageQuery.GetQueryFields;var i, iFieldsCount: Integer;begin iFieldsCount := 0 con DBGride1.DataSource.DataSet comienza para i := 0 a Fields.Count - 1; hazlo si Fields[i].Visible y luego comienza FFields[iFieldsCount, 0] := Fields[i].FieldName; FFields[iFieldsCount, 1] := Fields[i].DisplayLabel; Inc(iFieldsCount); fin de ComboBox1.Items.Add; (FFields[i, 1]); end;end; Esto permite la carga dinámica de información de campo en tiempo de ejecución. Entonces mi configuración de filtro se ve así. si ComboBox1.Text <> '' entoncesbeginClientDataSet.Filtered := False ClientDataSet.Filter := FFields[ComboBox1.ItemIndex, 0] + '''' + Edit2.Text + ''''; end; este método sin duda aumenta la flexibilidad del código y aumenta la reutilización del código, porque el código está bien aislado de los datos cambiantes. Por lo tanto, se puede decir que es conveniente siempre que agregue el campo privado FFields: array[0..20, 0..2] de cadena en otro FORMULARIO que también implemente esta función y utilice el proceso anterior de carga dinámica de datos. Se logra la reutilización de campos establecidos. Pero esta reutilización no es muy buena porque no hemos conseguido una buena encapsulación. Esto conduce a código duplicado disperso por todas partes de su programa (a menudo usa COPY para obtener la reutilización de esta función, porque el código anterior no tiene una buena encapsulación). Si algún día deseas modificar la función de carga de datos, tendrás que encontrar un lugar para copiar la función y tendrás que modificar el código disperso en otros lugares. Así que lo refactoricé nuevamente y encapsulé aún más el código. El código es el siguiente: unidad uDataSetFieldsInfo; // Descripción: la unidad incluye la clase TDataSetFieldsInfo, que encapsula la adquisición de información de subsegmentos del conjunto de datos. // Y proporciona una interfaz de método para mostrar información en el campo de visualización de la lista del cuadro combinado y obtener el nombre de la subsección correspondiente // Creado: wuchhao // Fecha: 2003.5interfaceuses Classes, DBClient, StdCtrls type TDataSetFieldsInfo = class private FFieldsList: TStrings public constructor; Crear; destructor Destruir; anular; procedimiento GetDataSetFields(Fuente: TClientDataSet); procedimiento ShowFieldsInfo(Destino: TComboBox); función GetFieldsNameByDisplayLabel(DisplayLabel: string): cadena; fin;implementación{ TDataSetFieldsInfo }constructor TDataSetFieldsInfo.Create;begin FFieldsList := TStringList.Create;end;destructor TDataSetFieldsInfo.Destroy;begin FFieldsList.Free; heredado;end;procedimiento TDataSetFieldsInfo.GetDataSetFields(Fuente: TClientDataSet);var i: Integer;begin FFieldsList.Clear con Source do start for i := 0 to Fields.Count - 1 do if; Campos[i].Visible y luego comenzar FFieldsList.Add(Fields[i].DisplayLabel); FFieldsList.Add(Fields[i].FieldName end; end;end;function TDataSetFieldsInfo.GetFieldsNameByDisplayLabel( DisplayLabel: string): string;var index: Integer;begin Resultado: = ''; índice := FFieldsList.IndexOf(DisplayLabel); <> -1 luego Resultado := FFieldsList.Strings[index+1] ;end;procedimiento TDataSetFieldsInfo.ShowFieldsInfo(Target: TComboBox);var i: Integer;begin Target.Items.Clear i:=0; .Count comienza Target.Items.Add(FFieldsList.Strings[i]); i:= i+ 2; end;end;end. La unidad uDataSetFieldsInfo encapsula los datos y métodos relacionados con la realización de las funciones descritas en este artículo y los encapsula en una clase, implementando así el principio Abrir-Cerrar en el diseño orientado a objetos. La clase se convierte en una caja negra, por lo que se puede reutilizar fácilmente (reutilización de caja negra) sin preocuparse por la duplicación del código. Al mismo tiempo, debido a que encapsula información relacionada con funciones, las responsabilidades de la clase están claramente definidas (responsabilidad única) y tiene suficiente granularidad y buena encapsulación. TdataSetFieldsInfo aísla efectivamente el cuadro combinado de los datos cambiantes, lo que en última instancia mejora el grado de reutilización del código y al mismo tiempo reduce las responsabilidades de la clase FORM y la cantidad de números mágicos codificados. Aquí está el nuevo código: Primero declare una referencia a la clase TdataSetFieldsInfo en el FORMULARIO. ... Llamar cuando se crea FORM: FFieldsInfo := TDataSetFieldsInfo.Create;FFieldsInfo.GetDataSetFields(cdMaster);FFieldsInfo.ShowFieldsInfo(ComboBox1) En este momento, mi configuración de filtro se convierte en: if ComboBox1.Text <> '' thenbeginClientDataSet.Filtered); := Falso; ClientDataSet.Filter := FFieldsInfo.GetFieldsNameByDisplayLabel(ComboBox1.Text) + '''' + Edit2.Text + ''''; ClientDataSet.Filtered := True;end; nombre. Este artículo es un ejemplo simple de refactorización de código. Creo que la clase que implementé anteriormente se puede escribir de muchas maneras y tiene mejores algoritmos. Esto es solo para dar una idea sobre cómo refactorizar el código. Para mejorar la calidad de nuestro código y su mantenibilidad y escalabilidad, exploraremos ideas sobre la programación OOD.