1. La implementación de objetos comerciales. Las clases que encapsulan reglas comerciales son la base de la verdadera programación orientada a objetos. En este artículo, cubriremos todos los aspectos de la programación y cuestionaremos algunas de nuestras formas habituales de escribir programas Delphi. El concepto básico detrás de estos métodos de diseño es la encapsulación: diseñar un conjunto de clases con interfaces (métodos) claramente definidas que tienen métodos para operar en sus propiedades. Este concepto se utilizará durante todo el programa y tiene un fuerte impacto en cómo se guardan y presentan los datos. Me gustaría presentarles a los lectores el artículo de Francis Glassborow sobre C ++. Aunque los lenguajes son diferentes, los excelentes conceptos de diseño de clases son independientes del lenguaje. La mayoría de los programas escritos en Delphi hoy en día no están orientados a objetos. El hecho de que exista un modelo de objetos en el lenguaje y utilice clases originales o nuevas no significa que el programa esté verdaderamente orientado a objetos. La reutilización del código termina cuando los controles de terceros se arrastran a las ventanas, pero las interdependencias entre ventanas y unidades proliferan rápidamente. (!!!) Si desea cambiar la base del programa en el futuro (como cambiar a una base de datos diferente o pasar de una estructura de dos niveles a una estructura de tres niveles), será muy complicado o costoso. Si el programa está realmente escrito de manera orientada a objetos, será más conveniente que restrictivo. Por supuesto, escribir un programa de este tipo requiere mejorar los conceptos y hay una falta de productividad al principio. La mayoría de los equipos de desarrollo no están dispuestos a hacerlo ni a considerarlo. Espero que a través de este artículo te muestre cómo escribir mejores programas. El resultado es un sistema más confiable, fácil de mantener, consistente en estilo, flexible, reutilizable y que funciona mejor que los programas escritos de manera tradicional. Especialmente para programas grandes, los programas cuyo código sea claro y verdaderamente orientado a objetos requerirán menos recursos de mantenimiento que el mismo programa escrito de forma tradicional. La mayor confiabilidad de los programas orientados a objetos proviene del hecho de que los datos y las operaciones están encapsulados en clases bien definidas. El compilador aplica las clases, métodos y propiedades correctos en el código mediante una potente verificación de tipos, y no debería haber posibilidad de malinterpretar la intención del código si un cambio futuro afecta a todo el programa. Cuando las clases se usan correctamente, las relaciones entre ellas son evidentes y la mayor parte del código se centra realmente en la esencia del programa, en lugar de pensar en detalles como cómo se conservan los datos. La simplicidad y la coherencia en todo el código mejorarán significativamente la capacidad de mantenimiento del programa. Como veremos, el uso extensivo de la herencia de clases aumenta la productividad y la confiabilidad y mejora la coherencia. Estas coherencias se reflejan en el código mostrado, incluido el comportamiento de las clases, cómo se almacenan los datos y cómo la interfaz de usuario presenta los datos. Dado que la mayor parte de la funcionalidad se proporciona en las clases base, puedes cambiar fundamentalmente tu programa cambiando rápidamente su comportamiento. (Por ejemplo, la interfaz de interacción del usuario se cambia de un formulario controlado por ventana a uno basado en HTML). Estas clases base se pueden diseñar para que sean independientes del programa, de modo que un segundo programa similar obtenga inmediatamente un impulso en la productividad. Un buen conjunto de clases base puede proporcionar una mejora significativa de hasta el 50 % para un programa modesto en términos de tiempo, gasto y confiabilidad. Lo primero que hay que enfatizar es que cambiar al verdadero desarrollo orientado a objetos no es un asunto trivial. Por primera vez, debe asegurarse de contar con asistencia experimentada, o el programa es pequeño y no hay una fecha límite de entrega urgente; Cabe señalar que una solución orientada a objetos (OO) no es dictar qué clases deben usarse y qué clases no deben usarse en el programa. Si una empresa desarrolla sus propios controles visuales o utiliza controles visuales de terceros, clases principales. El primer paso en el diseño de cualquier programa orientado a objetos es considerar qué clases son necesarias. Se trata de un paso absolutamente fundamental, sujeto a las garantías técnicas de otros desarrollos, ya que los errores en las primeras etapas serán costosos de corregir. Al diseñar nuestras clases, generalmente nos esforzamos por lograr un bajo acoplamiento y una alta cohesión: las clases son lo más independientes posible, pero se pueden combinar de alguna manera poderosa. Una forma de lograr este objetivo es dividir las clases en diferentes categorías según los diferentes roles que desempeñan en sus programas. La selección correcta de estos roles dará como resultado un conjunto cohesivo de clases. Existe un principio básico consistente en el diseño del rol de las clases: dividir las responsabilidades de la clase en presentación, aplicación y almacenamiento persistente de datos (generalmente en una base de datos). Aunque esto es lo mismo que la partición de programas de bases de datos de tres niveles, es importante tener en cuenta que este concepto de partición se puede implementar en una variedad de entornos: desde programas de un solo chip hasta programas distribuidos de varios niveles. El grupo de clases que componen la lógica de la aplicación es responsable del trabajo más difícil, como responder a las solicitudes de acciones del usuario y procesar datos. Algunas clases de esta capa representan entidades del mundo real y son modeladas por el sistema. Estas clases a menudo se denominan "clases de negocios" o "clases de dominio problemático". Forman una parte vital de cualquier programa orientado a objetos y, debido a que otras clases soportarán estas clases de alguna manera, se convierten en el foco de todos los desarrolladores. Identificar qué objetos de negocio están presentes en un programa en particular es generalmente una cuestión de experiencia e instinto, aunque existe toda una disciplina (¿o arte?) en este proceso. Las ventajas de la orientación a objetos sobre las técnicas tradicionales como SSADM(1) están presentes. a lo largo del análisis, diseño y El proceso de mantenimiento de entidades: Cada objeto de negocio se puede representar mediante análisis orientado a objetos (OOA), diseño orientado a objetos (OOD) y programación orientada a objetos (OOP). Exploraremos algunas técnicas para identificar objetivos comerciales adecuados más adelante. Primero asumimos que se han completado los siguientes procesos. La intercomunicación de clases entre diferentes capas (presentación, aplicación y persistencia) está claramente definida e interconectada. La relación entre estas clases se muestra en la Figura 1. Las flechas en la figura muestran que las clases en la misma capa pueden llamar a métodos en otra clase. Esta imagen también muestra que las clases de la capa de presentación (interfaz de usuario) pueden operar la capa de aplicación u otras clases en la interfaz de usuario. La capa de aplicación (objetos comerciales) puede operar las clases de la capa de aplicación y llamar a los métodos de persistencia. capa La capa de persistencia solo responde a la solicitud de la capa de aplicación. Objetos de negocio Para demostrar cómo se implementan los objetos de negocio, veremos a continuación un programa simplificado con entidades de inventario, cliente y pedido (una empresa proporciona una cierta cantidad de bienes y los clientes compran estos bienes). Nuestro análisis inicial determinó que se requerían tres objetos comerciales para representar a estas entidades. Habrá tres clases en nuestro programa Delphi: TStockItem, TCustomer y Torder. Las interfaces públicas de estas clases se muestran en el Listado 1. Cabe señalar aquí que las características de estas clases están expuestas al exterior a través de propiedades (PRoperty): este es un diseño de clase simple y beneficioso y controla el acceso externo a través de propiedades. Además, estas propiedades deben estar en el área publicada de la clase (por razones que se mencionarán más adelante) y se les deben asignar valores predeterminados apropiados. Aunque estas calificaciones de propiedad solo se usan cuando se transmiten clases, le dan a cada propiedad un valor inicial apropiado y hacen que el código sea más autodescriptivo. Marco de primera clase En las etapas iniciales de desarrollo del programa, hemos identificado e implementado tres objetos comerciales. Estos tres objetos juegan un papel común: representar de alguna manera entidades del mundo real. Por lo tanto, queremos que tengan propiedades similares y niveles apropiados para las entidades del mundo real. Le daremos a cada objeto una clase base común llamada TPDObject (objeto de dominio del problema). Con el tiempo agregaremos métodos y propiedades públicos a esta clase y TPDObject seguirá ampliándose. Cabe señalar que TPDObject no debe (nunca) tener ningún elemento relacionado con una aplicación específica. Como clase independiente del programa, se coloca en una unidad independiente y forma la base del marco: un conjunto de clases que se pueden reutilizar en muchos programas. En el futuro, nuestro marco se ampliará enormemente para formar clases base que proporcionen importantes funciones independientes del programa y puedan usarse rápidamente en sistemas específicos. Nuestros TStockItem, TCustomer y Torder son objetos personalizados para sistemas específicos de TPDObject. TMyAppPDObject es una clase heredada de TPDObject. Aunque su parte de implementación está vacía, es una buena demostración si agregamos ciertos elementos a un programa específico y afectamos todas las clases de dominio problemáticas en el programa, de esta manera La jerarquía de clases debería ser más apropiada. El código inicial para el marco aparece en la lista. La clase TPDObject también proporciona solo un ID de atributo de solo lectura, su tipo es TobjectID. Este atributo le da a cada objeto un identificador: consideraremos dos instancias del mismo tipo e ID como el mismo objeto. Aquí el ID se declara intencionalmente como su propio tipo para evitar que se asigne directamente a un valor de otro tipo estándar. El tipo de TobjectID no se eligió específicamente: aquí elegí un número entero, que también puede ser una clase especializada en ciertos casos. Aunque usar clases como ID parece ser un enfoque más puro orientado a objetos, basado en el hecho de que las clases en nuestro dominio problemático se crearán y publicarán miles de veces durante la ejecución del programa, para evitar la carga adicional al crear y liberar objetos, no hice esto (como purista incluyo TobjectID en TPDobject como un objeto compuesto). En el código hay un par de funciones que convierten cadenas a nuestros tipos de identificación de objetos y una constante que sirve como valor inicial cuando no se realiza ninguna asignación. Hay muchas clases en las que se menciona la identificación de objetos: algunas dicen que a todos los objetos comerciales se les debe dar una identificación (incluso un GUID) que no se repita dentro del programa cuando se crean. De hecho, lo realmente importante es poder distinguir entre diferentes objetos en un contexto determinado, y mantener esto simple tendrá beneficios obvios de rendimiento y espacio de almacenamiento. Preguntas sobre especificaciones: para fortalecer algunos conceptos y prácticas de diseño al diseñar marcos de clases, haré algunas preguntas y pediré a los lectores que piensen en los principios básicos detrás de ellas. Mencioné que el verdadero diseño orientado a objetos no prohíbe el uso de clases específicas, pero hay una excepción importante. ¿Cuál es esta excepción (la respuesta se encuentra en la Figura 1)? ((( Listado 1: una unidad de dominio de problema específica de la aplicación (abreviada))))unit ProblemDomain;interfaceuses Framework;type TMyAppPDObject = class (TPDObject) end TStockItem = class (; TMyAppPDObject ) nombre de propiedad publicada: cadena; propiedad Cantidad en stock: propiedad cardinal predeterminada 0; propiedad de moneda; precio minorista: fin de moneda; TCustomer = class (TMyAppPDObject) … ; TOrder = class (TMyAppPDObject) … ;implementationend.((( End Listing 1 )))((( Listing 2 - Una unidad de marco independiente de la aplicación )))unit Framework;interfaceconst NotAssigned = 0; tipo TObjectID = tipo Integer TPDObject = clase privada FID: TObjectID propiedad pública ID: TObjectID leer FID predeterminado NotAssigned; end;function StrToID (Valor: String): TObjectID;function IDToStr (Valor: TObjectID): String;implementación…end.((( End Listing 2 )))(1) SSADM (Análisis de sistemas estructurados y diseño de sistemas) se estableció en 1981 Sitio web de la Agencia Central de Informática y Telecomunicaciones (CCTA) del Gobierno Británico: http://www.ccta.gov.uk; ) desarrolló métodos estándar de análisis y diseño de software. Philip Brown es consultor de diseño de sistemas y desarrollador, presentador y formador activo. Promocionará los beneficios de técnicas sólidas de OO para ofrecer mejores aplicaciones en cualquier oportunidad. Puede contactarlo en [email protected].