VB.NET ¿Cuál es el propósito de una clase o módulo?

Salsa de novato aquí … Entonces, traté de encontrar la respuesta, pero no pude.

¿Cuál es el propósito de tener una clase o módulo? Todo lo que leo trata de decirme qué es, pero no para qué sirve. ¿Por qué tendría que hacer uno?

Todo lo que leo parece hacer suposiciones sobre la persona que lee el tutorial, como si supiera mucho.

Un módulo es muy similar a una clase que solo contiene miembros compartidos. De hecho, en C #, no existe una construcción como un “módulo”. No puedes escribir ninguna aplicación sin tener al menos un módulo o clase, así que sospecho que tu verdadera pregunta no es “por qué usar clases y módulos”, sino “por qué usar múltiples clases y módulos y cuándo es apropiado comenzar uno nuevo”. . Dado que los módulos y las clases son esencialmente lo mismo, me centraré solo en por qué tendrían múltiples clases. Hay esencialmente cuatro razones principales para crear una nueva clase:

  1. Almacenar datos en elementos discretos
  2. Organiza tu código
  3. Proporcione costuras en su código
  4. Divida su código en capas y soporte n-tiers

Ahora, veamos cada uno con más detalle:

Almacenar datos en elementos discretos

Muchas veces necesita almacenar datos múltiples sobre un solo elemento y pasar esos datos entre los métodos como un solo objeto. Por ejemplo, si escribe una aplicación que funciona con una persona, es probable que desee almacenar datos múltiples sobre la persona, como su nombre, edad y título. Obviamente, puede almacenar estos tres datos como tres variables separadas, y pasarlos como parámetros separados a los métodos, tales como:

 Public Sub DisplayPerson(name As String, age As Integer, title As String) Label1.Text = name Label2.Text = age.ToString() Label3.Text = title End Sub 

Sin embargo, a menudo es más conveniente pasar todos los datos como un solo objeto, por ejemplo, podría crear un MyPersonClass , como este:

 Public Class MyPersonClass Public Name As String Public Age As Integer Public Title As String End Class 

Y luego podría pasar todos los datos sobre una persona en un solo parámetro, como este:

 Public Sub DisplayPerson(person As MyPersonClass) Label1.Text = person.Name Label2.Text = person.Age.ToString() Label3.Text = person.Title End Sub 

Al hacerlo de esta manera, es mucho más fácil en el futuro modificar a su persona. Por ejemplo, si necesita agregar la capacidad de almacenar una habilidad para la persona, y no había puesto los datos de la persona en una clase, tendría que ir a cada lugar en el código que pasa datos de la persona y agregar el parámetro adicional . En un proyecto grande, podría ser muy difícil encontrar todos esos lugares para arreglar, lo que podría provocar errores. Sin embargo, la necesidad de la clase se vuelve aún más evidente cuando comienza a necesitar almacenar una lista de varias personas. Por ejemplo, si necesita almacenar los datos para 10 personas diferentes, necesitaría una lista o matriz de variables, por ejemplo:

 Dim names(9) As String Dim ages(9) As Integer Dim titles(9) As String 

Por supuesto, no es del todo obvio que los names(3) y la age(3) almacenan datos para la misma persona. Eso es algo que solo debes saber, o tienes que escribirlo en un comentario para que no lo olvides. Sin embargo, esto es mucho más limpio y fácil de hacer cuando tienes la clase para almacenar todos los datos de una persona:

 Dim persons(9) As Person 

Ahora, es completamente obvio que las persons(3).Name y persons(3).Age son datos para la misma persona. De esa manera, es autodocumentado. No se necesitan comentarios para aclarar tu lógica. Como resultado, una vez más, el código será menos propenso a errores.

A menudo, las clases contendrán no solo los datos de un artículo en particular, sino también los métodos que actúan sobre esos datos. Este es un mecanismo conveniente. Por ejemplo, es posible que desee agregar un método GetDesciption a la clase de persona, como por ejemplo:

 Public Class MyPersonClass Public Name As String Public Age As Integer Public Title As String Public Function GetDescription() As String Return Title & " " & Name End Function End Class 

Entonces puedes usarlo así:

 For Each person As MyPersonClass In persons MessageBox.Show("Hello " & person.GetDescription()) Next 

Lo cual, como estoy seguro de que estarás de acuerdo, es mucho más limpio y fácil que hacer algo como esto:

 For i As Integer = 0 To 9 MessageBox.Show("Hello " & GetPersonDescription(title(i), names(i))) Next 

Ahora digamos que desea almacenar múltiples apodos para cada persona. Como puede ver fácilmente, las persons(3).Nicknames(0) son mucho más simples que algunas locas persons(3).Nicknames(0) bidimensionales, como nicknames(3)(0) . ¿Y qué sucede si necesita almacenar datos múltiples sobre cada apodo? Como puede ver, el hecho de no usar las clases se complicaría muy rápido.

Organiza tu código

Cuando escribes un progtwig extenso, puede llegar a ser muy complicado muy rápidamente y dar lugar a un código muy defectuoso si no organizas correctamente tu código. El arma más importante que tienes en esta batalla contra el código de spaghetti es crear más clases. Idealmente, cada clase contendrá solo los métodos lógicamente directamente relacionados entre sí. Cada nuevo tipo de funcionalidad se debe dividir en una nueva clase bien nombrada. En un proyecto grande, estas clases deberían estar organizadas en espacios de nombres separados, pero si al menos no las divide en clases, realmente va a hacer un desastre. Por ejemplo, supongamos que tienes todos los siguientes métodos arrojados al mismo módulo:

  • GetPersonDescription
  • GetProductDescription
  • FirePerson
  • SellProduct

Estoy seguro de que aceptaría que es mucho más fácil seguir el código si estos métodos se dividieran en clases separadas, como por ejemplo:

  • Person
    • GetDescription
    • Fire
  • Product
    • GetDescription
    • Sell

Y ese es solo un ejemplo muy, muy simple. Cuando tienes miles de métodos y variables que tratan de muchos artículos diferentes y diferentes tipos de artículos, estoy seguro de que puedes imaginar fácilmente por qué las clases son importantes para ayudar a organizar y auto-documentar el código.

Proporcione costuras en su código

Este puede ser un poco más avanzado, pero es muy importante, así que intentaré explicarlo en términos simples. Supongamos que crea una clase trace-logger que escribe entradas de registro en un archivo de registro de seguimiento. Por ejemplo:

 Public Class TraceLogger Public Sub LogEntry(text As String) ' Append the time-stamp to the text ' Write the text to the file End Sub End Class 

Ahora, supongamos que quiere que la clase de registrador pueda escribir en un archivo o en una base de datos. En este punto, resulta obvio que escribir la entrada de registro en el archivo es realmente un tipo de lógica separada que debería haber estado en su propia clase todo el tiempo, por lo que puede dividirla en una clase separada, como esta:

 Public Class TextFileLogWriter Public Sub WriteEntry(text As String) ' Write to file End Sub End Class 

Ahora puede crear una interfaz común y compartirla entre dos clases diferentes. Ambas clases manejarán las entradas del registro de escritura, pero cada una de ellas realizará la funcionalidad de maneras completamente diferentes:

 Public Interface ILogWriter Sub WriteEntry(text As String) End Interface Public Class TextFileLogWriter Implements ILogWriter Public Sub WriteEntry(text As String) Implements ILogWriter.WriteEntry ' Write to file End Sub End Class Public Class DatabaseLogWriter Implements ILogWriter Public Sub WriteEntry(text As String) Implements ILogWriter.WriteEntry ' Write to database End Sub End Class 

Ahora que ha roto la lógica de acceso a datos en sus propias clases, puede refactorizar su clase de registrador de esta manera:

 Public Class TraceLogger Public Sub New(writer As ILogWriter) _writer = writer End Sub Private _writer As ILogWriter Public Sub LogEntry(text As String) ' Append the time-stamp to the text _writer.WriteEntry(text) End Sub End Class 

Ahora puede reutilizar la clase TraceLogger en muchas más situaciones sin tener que tocar esa clase. Por ejemplo, podría darle un objeto ILogWriter que escriba las entradas en el registro de eventos de Windows, o en una hoja de cálculo, o incluso en un correo electrónico, todo ello sin tocar la clase TraceLogger original. Esto es posible porque ha creado una costura en su lógica entre el formateo de las entradas y la escritura de las entradas.

Al formateo no le importa cómo se registran las entradas. Lo único que le importa es cómo formatear las entradas. Cuando necesita escribir y entrar, simplemente le pide a un objeto de escritor por separado que haga esa parte del trabajo. Cómo y qué hace ese escritor realmente internamente es irrelevante. Del mismo modo, al escritor no le importa cómo se formatea la entrada, solo espera que lo que se le pase sea una entrada válida ya formateada que deba registrarse.

Como habrás notado, no solo el TraceLogger ahora es reutilizable para escribir en ningún tipo de registro, sino que los escritores son reutilizables para escribir cualquier tipo de registro en esos tipos de registros. Podría reutilizar el DatabaseLogWriter , por ejemplo, para escribir registros de seguimiento y registros de excepción.

Un poco de incertidumbre con respecto a la dependency injection

Solo piénsate un poco, mientras hago esta respuesta un poco más larga con una diatriba sobre algo importante para mí … En ese último ejemplo, utilicé una técnica llamada dependency injection (DI). Se llama dependency injection porque el objeto de escritura es una dependencia de la clase de registrador y ese objeto de dependencia se inyecta en la clase de registrador a través del constructor. Podrías lograr algo similar sin la dependency injection haciendo algo como esto:

 Public Class TraceLogger Public Sub New(mode As LoggerModeEnum) If mode = LoggerModeEnum.TextFile Then _writer = New TextFileLogWriter() Else _writer = New DatabaseLogWriter() End If End Sub Private _writer As ILogWriter Public Sub LogEntry(text As String) ' Append the time-stamp to the text _writer.WriteEntry(text) End Sub End Class 

Sin embargo, como puede ver, si lo hace de esa manera, ahora deberá modificar esa clase de registrador cada vez que cree un nuevo tipo de escritor. Y luego, solo para crear un registrador, debe tener referencias de cada tipo diferente de escritor. Cuando escribes el código de esta manera, muy pronto, cada vez que incluyes una clase, de repente tienes que hacer referencia al mundo entero solo para hacer una tarea simple.

Otra alternativa al enfoque de dependency injection sería usar la herencia para crear múltiples clases de TraceLogger , una por tipo de escritor:

 Public MustInherit Class TraceLogger Public Sub New() _writer = NewLogWriter() End Sub Private _writer As ILogWriter Protected MustOverride Sub NewLogWriter() Public Sub LogEntry(text As String) ' Append the time-stamp to the text _writer.WriteEntry(text) End Sub End Class Public Class TextFileTraceLogger Inherits TraceLogger Protected Overrides Sub NewLogWriter() _Return New TextFileLogWriter() End Sub End Class Public Class DatabaseTraceLogger Inherits TraceLogger Protected Overrides Sub NewLogWriter() _Return New DatabaseLogWriter() End Sub End Class 

Hacerlo con herencia, así, es mejor que el enfoque de enumeración de modo, porque no tiene que hacer referencia a toda la lógica de la base de datos solo para iniciar sesión en un archivo de texto, pero, en mi opinión, la dependency injection es más limpia y más flexible .

Volver a un resumen de costuras lógicas

Entonces, en resumen, las costuras en su lógica son importantes para la reutilización, flexibilidad e intercambiabilidad de su código. En proyectos pequeños, estas cosas no son de sum importancia, pero a medida que los proyectos crecen, tener costuras claras puede volverse crítico.

Otro gran beneficio de crear costuras es que hace que el código sea más estable y comprobable. Una vez que sepa que el TraceLogger funciona, hay una gran ventaja de poder extenderlo para usos futuros, como escribir registros en una hoja de cálculo, sin tener que tocar la clase TraceLogger real. Si no tiene que tocarlo, no corre el riesgo de introducir nuevos errores y potencialmente comprometer el rest del código que ya lo usa. Además, se vuelve mucho más fácil probar cada pieza de tu código de forma aislada. Por ejemplo, si quisiera probar la clase TraceLogger , podría simplemente, para su prueba, hacer que use un objeto de escritura falso que simplemente se conecta a la memoria, a la consola, o algo.

Divida su código en capas y soporte N-Tiers

Una vez que haya organizado correctamente su código en clases separadas, donde cada clase solo es responsable de un tipo de tarea, puede comenzar a agrupar sus clases en capas . Las capas son solo una organización de alto nivel de su código. No hay nada específico en el lenguaje que haga que algo sea técnicamente una capa. Como no hay nada directamente en el idioma que aclare dónde comienza y termina cada capa, a menudo las personas colocan todas las clases para cada capa en espacios de nombres separados. Entonces, por ejemplo, puede tener espacios de nombres que se vean así (donde cada espacio de nombre es una capa separada):

  • MyProduct.Presentation
  • MyProduct.Business
  • MyProduct.DataAccess

Por lo general, siempre debe tener al menos dos capas en su código: la capa de presentación o interfaz de usuario y la capa de lógica de negocios. Si su aplicación tiene acceso a datos, normalmente también se coloca en su propia capa. Cada capa debe ser, tanto como sea posible, independiente e intercambiable. Entonces, por ejemplo, si nuestra clase TraceLogger en el ejemplo anterior está en una capa empresarial, debería ser reutilizable por cualquier tipo de UI.

Las capas se expanden sobre todos los temas anteriores al proporcionar más organización, auto-documentación, reutilización y estabilidad. Sin embargo, otro beneficio importante para las capas es que resulta mucho más fácil dividir la aplicación en varios niveles. Por ejemplo, si necesita mover su negocio y la lógica de acceso a datos a un servicio web, será muy simple hacerlo si ya ha escrito su código limpiamente en capas definidas. Sin embargo, si toda esa lógica está entremezclada e interdependiente, entonces será una pesadilla intentar romper solo el acceso a los datos y la lógica comercial en un proyecto separado.

El final de lo que tengo que decir

En resumen, nunca es necesario crear más de una clase o módulo. Siempre será posible escribir toda tu aplicación en una sola clase o módulo. Al fin y al cabo, se desarrollaron sistemas operativos completos y paquetes de software, incluso antes de que se inventaran los lenguajes orientados a objetos. Sin embargo, hay una razón por la cual los lenguajes de progtwigción orientada a objetos (OOP) son tan populares. Para muchos proyectos, la orientación a objetos es increíblemente beneficiosa.

Una clase es el mecanismo para encapsular el estado (datos) y el comportamiento (métodos).

Necesita utilizar clases si desea tener algún tipo de abstracción en su código: formas de organizar su código para su uso.

No tenerlos significa que tu código está por todas partes y degenerará en algo que es difícil de cambiar y mantener.

La forma más básica que puede tomar un progtwig de computadora se llama Procedimiento : usted escribe una lista de instrucciones (líneas de código) para que la computadora la realice y luego el progtwig sale.

Sin embargo, muchos progtwigs de computadora están diseñados para ejecutarse independientemente del individuo que haga clic en “ejecutar” cada vez que sea necesario. Es este concepto de reutilización de código lo que es central para la mayoría de las discusiones sobre la escritura de software. Un Módulo le permite almacenar código en un contenedor y consultarlo en otras partes de su progtwig.

Una clase es un concepto más general en la progtwigción orientada a objetos, que le permite definir una “cosa” y luego crearla varias veces mientras su progtwig se está ejecutando.

Supongamos que quiere crear un juego Virtual Pet en Visual Basic. Permite que el usuario agregue tantos animales diferentes como quiera y comienza a darse cuenta de que hacer un seguimiento de esto es muy complicado. Al usar clases, esto se vuelve realmente fácil …

 Class PetDog Private _id As Integer Public Name As String Public Breed As String Public Sub Bark() Console.WriteLine(Name + " says Woof!") End Sub End Class 

Una vez que haya escrito este código, permitir que el usuario agregue otro perro a su zoológico de mascotas se vuelve tan simple como esto:

 Dim Dog1 As New PetDog() Dim Dog2 As New PetDog() 

Ahora, puedes interactuar con Dog1 y Dog2 independientemente el uno del otro, a pesar de solo definirlo una sola vez en tu código.

 Dog1.Name = "Fido" Dog2.Breed = "Poodle" Dog1.Bark() 

El fragmento de arriba imprimiría “¡Fido dice Woof!”.

Espero que ayude 🙂

Si va a crear su tipo personalizado y luego crear objetos de ese tipo, use una clase.

Si está tratando con las clases de otra persona y necesita implementar alguna funcionalidad rápida y sucia para mejorarlas, use módulos.

Los desarrolladores de C # podrían mostrar ahora una cara agria, porque usaría métodos compartidos de una clase compartida en lugar de un módulo en C #, en última instancia porque C # no tiene módulos. Entonces usarías clases en ambos casos en C #. Y deberías hacer lo mismo en VB.NET, realmente. Le da preocupación de separación del espacio de nombres, por lo que su intellisense es más organizado. Con los módulos, todos sus métodos públicos de todos los módulos están en el cubo global de métodos: más desorden para manejar.

El único buen uso para los módulos en VB.NET es cuando se escriben métodos de extensión.

Clases, formularios y código: “Módulos” son todos los tipos de módulos en VB.

Los módulos son simplemente contenedores con nombre para el código, y todo el código tiene que estar en algún tipo de módulo. En su forma más simple, son una forma de organizar sus rutinas en grupos significativos.

Los más básicos, los llamados “Módulos” (o “módulos de código” como se los llamó una vez para distinguirlos del concepto más general de módulos) brindan poco más que eso, más una forma de declarar variables que viven fuera de cualquier única rutina y no desaparecen cuando sale de la rutina, y una manera fácil de asociar qué código / módulo (s) están en qué archivos fuente.

Las clases son un tipo de Módulo (*) más poderoso que puede “Instalarse”, lo que significa que puedes tratarlas como un tipo de datos, crear copias múltiples de ellas con diferentes valores / contenidos, asignarlas a variables, pasarlas hacia y desde funciones y otros métodos, etc. Estas copias o “instancias” se denominan más comúnmente “Objetos”.

Los formularios son solo un tipo especial de clase que se integran de forma automática mediante dispositivos visuales y controles para ayudarlo a crear una interfaz gráfica de usuario.

(* – Tenga en cuenta que hoy esto se enseña al revés: las clases son el concepto general y los códigos-mdulos de VB son solo una clase especializada muy limitada llamada “Singleton”. Pero tanto históricamente como en la tradición de Basic, era Módulos mucho antes de clases.)

Parece que está familiarizado con algún nivel de scripting, pero no necesariamente con progtwigción orientada a objetos.

La razón para usar clases o módulos (que son ambos objetos) es que, al igual que las funciones permiten la reutilización del código, los objetos permiten la reutilización.

Más allá de la reutilización, tienen la ventaja de que pueden contener datos (propiedades) y funciones. Por ejemplo, una clase Person podría tener propiedades como nombre, fecha de nacimiento, etc., y un método para calcular su edad.

De esta forma, cada vez que tuviera una nueva persona, crearía una nueva instancia de esa persona, y sería fácil calcular su edad (según su fecha de nacimiento y la fecha actual).

Alternativamente, podría hacer todo esto de manera similar escribiendo una función para calcular la edad y crear una matriz para cada persona, y luego llamar a su función de edad de cálculo pasando la matriz de edad, pero no tendría el mismo nivel de reutilización. .

Para encontrar artículos útiles, puede buscar en Google las introducciones a la progtwigción orientada a objetos.

En palabras simples, una Clase o un Módulo para mí en progtwigción se usa para no dar forma a mucho guión cuando se carga. Entonces, debemos reducirlos a clases y módulos.