Singleton más legible y accesible en VB.NET

Jueves 26 de Julio de 2007 a las 23:59

Uno de los patrones de diseño más conocidos y utilizados (si no el que más) es el patrón singleton, que permite garantizar la existencia de una única instancia de una clase evitando la creación de objetos de ese tipo declarando el constructor como privado o protegido. Otra de las ventajas de este patrón es que permite centralizar en un único punto todos los accesos a la instancia.

Una posible implementación en Visual Basic .NET sería la siguiente:

 

VB.NET:
  1. Public Class Singleton
  2.  
  3.     Private Sub New()
  4.     End Sub
  5.  
  6.     Private Shared _instancia As Singleton
  7.  
  8.     Public Shared ReadOnly Property Instancia() As Singleton
  9.         Get
  10.             If _instancia Is Nothing Then
  11.                 _instancia = New Singleton
  12.             End If
  13.  
  14.             Return _instancia
  15.         End Get
  16.     End Property
  17. End Class

 

La forma de acceder a una propiedad de esta clase para asignarle un valor sería:

Singleton.Instancia.MiPropiedad = "miValor"

Esta forma de acceder a una propiedad es un poco artificial y no resulta tan legible o natural como:

Singleton.MiPropiedad = "miValor"

Para conseguir acceder de estar forma a una propiedad de nuestra instancia deberemos crearnos un modulo:

 

VB.NET:
  1. <Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _
  2. Public Module Auxiliar
  3.     Public ReadOnly Property SingletonInst() As Singleton
  4.         Get
  5.             Return Singleton.Instancia
  6.         End Get
  7.     End Property
  8. End Module

 

Ahora para acceder a la propiedad simplemente tendremos que escribir:

SingletonInst.MiPropiedad = "miValor"

Esta solución únicamente es valida en Visual Basic.NET debido a que en C# no existen los módulos.

Detectar los cambios de la IP

Martes 24 de Julio de 2007 a las 23:51

A la hora de contar las visitas que tiene un sitio web es interesante no computar tus propias visitas que en algunos momentos pueden llegar a ser numerosas y que falsean las estadísticas reales. Para evitar esto los sistemas de estadísticas como el statcounter o el Google Analytics cuentan con la posibilidad de no contabilizar las visitas provenientes de una determinada IP.

El problema es que es bastante común tener direcciones IP dinámicas que cambian de vez en cuando, lo que obliga a tener que estar comprobando frecuentemente si tu IP actual coincide con la que estás filtrando en los servicios de estádisticas y si no es así actualizar las IP de los filtros.

En el caso de que se olvide hacer esta comprobación y cambies de IP las estadísticas habrán estado contando todas tus visitas.

Para evitar está situación he creado una pequeña aplicación en Visual Basic.NET que apenas cuenta con media docena de líneas de código y que configurada para que se arranque al iniciar windows realizará la comparación de la IP actual y la anterior IP y en el caso de que sea diferente mostrará un aviso.

En el área de descargas está disponible el ejecutable.

El código de esta pequeña aplicación creada en VB.NET es el siguiente:

 

VB.NET:
  1. Option Strict On
  2. Option Explicit On
  3.  
  4. Module Programa
  5.  
  6.     Sub Main()
  7.         Dim IPs As System.Net.IPHostEntry = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName())
  8.  
  9.         If IPs.AddressList(0).ToString <> My.Settings.IP Then
  10.             MsgBox("Ha cambiado la IP de la máquina", MsgBoxStyle.Information, "Atención")
  11.             My.Settings.IP = IPs.AddressList(0).ToString
  12.             My.Settings.Save()
  13.         End If
  14.     End Sub
  15.  
  16. End Module

Dotando a los controles de .NET de un borde personalizado

Miércoles 18 de Julio de 2007 a las 23:57

Sorprendentemente los controles de .NET no admiten apenas estilos de borde. Por ejemplo el control listbox solo permite dibujar el borde de tres formas: hundido, con una línea negra o sin borde.

El intellisense que desarrollé hace tiempo para el editor de código se basaba en un listbox y no tenía una apariencia adecuada ni similar a los del intellisense de los IDES habituales debido al borde que tenía que era el borde hundido que viene por defecto en dicho control.

La primera forma de implementar los bordes que me vino a la cabeza fue crear un control que heredara de listbox, es la forma más lógica de implementarlo debido a lo que se busca es un listbox con cierta funcionalidad adicional. Sin embargo el control listbox no implementa el evento paint y aunque lo hereda de la clase Control nunca se levanta. De igual forma si se sobrescribe el método onpaint tampoco se ejecuta nunca.

La siguiente opción que se me ocurrió fue crear un control de usuario compuesto de un listbox y un picturebox, un panel o similar que contuviera el listbox y que sobresaliera dos pixels por cada uno de los lados del listbox. En esos pixeles sería donde dibujaría los bordes valiéndome del evento paint. Esta opción tiene un importante inconveniente y es que al no heredar de listbox sino de la clase UserControl no implementa todos los métodos, propiedades y eventos de listbox. En este punto habría dos opciones, la fácil que consistiría en hacer publico el listbox. Esta opción rompe con uno de los pilares de la orientación a objetos que es la encapsulación y el código que utilizara el control tendría que hacer utilizar por ejemplo listBoxConBorde.ListboxInterno.SelectedIdex en vez de listBoxConBorde.SelectedIdex que sería lo deseable.
La otra opción sería recubrir las propiedades, métodos y eventos del listbox en el control de usuario, creando en el control de usuario tantas propiedades, métodos y eventos como tenga el listbox. Estos miembros del control de usuario simplemente llamarían a los miembros homónimos del listbox. Esta opción me parece más adecuada que la anterior pero mucho mas tediosa de implementar.

Finalmente opté por una solución que me ha parecido mucho más acertada, sencilla y genérica. Consiste en crear un control llamado "Borde" que dibuje el borde de cualquier control. Hereda de la clase "Control" y consta de dos propiedades:

  • El tipo de borde (que admite los siguientes valores Elevado, ElevadoDobleLinea, Hundido, ElevadoYHundido y HundidoYElevado)
  • El control asociado al que se le dibujará el borde.

Además del código para realizar el dibujo del borde también se encarga de adecuar su tamaño y posición a la del control asociado.

Extender el control para añadir nuevos tipos de bordes con diferentes efectos sería una labor bastante sencilla de realizar.

La nueva apariencia del intellisense estableciendo el borde a ElevadoDobleLinea es la siguiente:


Intellisense con el nuevo borde.
Intellisense con el nuevo borde.


Intellisense."
Intellisense anterior.

 

En la sección de descargas se puede encontrar el código completo en VB.NET del control.

Combatiendo el spam

Martes 17 de Julio de 2007 a las 23:58

Después de bastante tiempo sin escribir ningún post y tener también abandonada la programación de videojuegos retomo ambas actividades.

En todo este tiempo en blog se me ha llenado de spam, no 3 o 4 comentarios, sino miles de ellos (en torno a 7000). Espero no haber borrado ningún comentario que no fuera spam por error durante las tareas de limpieza del blog.

Parece que es bastante habitual recibir spam en los blogs basados en wordpress.

Para evitar esta situación he decidido instalar un plugin antispam llamado wordverify. Este plugin se puede encontrar gratuitamente en esta página. De momento esta funcionando bien y no me ha llegado ni un solo comentario de spam desde que lo instalé. El original no funcionaba del todo correctamente así que he tenido que hacerle algunas modificaciones para corregirlas además de para traducir los textos. Si alguien está interesado que me lo pida. Se basa en solicitar a la persona que va a escribir el comentario que escriba una determinada palabra en una caja de texto con el fin de diferenciar a las personas y a los procesos automáticos de envio de Spam.

Para combatir el spam que llegaba mediante los trackbacks he utilizado el plugin Simple Trackback Validation que parece funcionar también correctamente.

Espero que estos plugins no presente ningún efecto secundario adverso. Si alguien tiene algún problema para escribir comentarios o de cualquier tipo con los filtros antispam por favor que me lo comunique a mi dirección de email brauXsoftYgmailZcom (eliminad la X, sustituid la Y por @ y la Z por .)

Nuevo ordenador MSX

Martes 28 de Noviembre de 2006 a las 23:59

Ha salido a la venta un nuevo modelo de ordenador MSX. Ha sido creado por la empresa D4 Enterprise. Es un MSX2 con 256KB de RAM. Es de reducidas dimensiones y cuenta con entradas y salidas para los periféricos de hoy en día tales como PS2, USB, ranuras para tarjetas SD/MMC, etc. pero también para los antiguos joysticks del clásico MSX y ranuras para los viejos cartuchos.

Hay que reconocer que tiene muy buena apariencia:

Nuevo MSX.
Nuevo MSX.

Se puede encontrar más información es esta página

Y para quien sepa japonés la pagina web de la empresa. En ella se pueden ver varias fotografías del ordenador.

A este paso, por el número de post que llevo sobre el MSX, voy a tener que crear una nueva categoría solo para el MSX.

El juego de la pelotita

Martes 14 de Noviembre de 2006 a las 23:53

Un juego curioso. Consiste en llevar la pelotita hasta el cuadrado rojo trazando caminos con el ratón. Es bastante fácil. Es un juego muy sencillo pero engancha. Está desarrollado con Flash.

Este es el enlace al juego

Accediendo a las tablas del sistema de Oracle

Domingo 12 de Noviembre de 2006 a las 23:58

En este artículo vamos a ver como acceder a las tablas del sistema de Oracle, para poder obtener información sobre las bases de datos, por ejemplo las tablas de una base de datos, los campos de los que consta, los procedimientos almacenados, las claves primarias, etc.

Esta información nos puede ser bastante útil por ejemplo para documentar la base de datos de forma automática, para crear los procedimientos almacenados automáticamente en función de los campos de las tablas o cualquier otra utilidad que se nos ocurra.

En el trabajo me he creado un generador de procedimientos almacenados que crea los PA de inserción, modificación, borrado y consulta de cualquier tabla de la base de datos, el cual nos está ahorrando mucho esfuerzo y horas de desarrollo a todo el equipo. La base de datos sobre la que estamos desarrollando la cambian continuamente, por lo que hay que rehacer los procedimientos almacenados cada dos por tres y gracias a está herramienta es automática la actualización de los PA.

A continuación paso a especificar algunas de las consultas a las tablas del sistema que pueden resultar de mayor utilidad:

La consulta que nos devuelve todas las tablas es la siguiente:


SELECT TABLE_NAME FROM USER_TABLES

Para obtener información sobre los campos o columnas de la tabla "NOMBRE_DE_LA_TABLA", incluyendo el nombre del campo, el tipo de datos (incluyendo precisión y escala si procede), si admite nulos y los comentarios que tenga asociados utilizaremos la siguiente consulta:


SELECT COLS.*, COM.COMMENTS
	FROM SYS.ALL_TAB_COLUMNS COLS
	LEFT JOIN SYS.ALL_COL_COMMENTS COM ON COLS.TABLE_NAME = COM.TABLE_NAME AND COLS.COLUMN_NAME = COM.COLUMN_NAME
	WHERE COLS.OWNER = USER AND COM.OWNER = USER AND COLS.TABLE_NAME = 'NOMBRE_DE_LA_TABLA' 

Si queremos obtener los campos que forman la clave principal o primary key (PK) de la tabla "NOMBRE_DE_LA_TABLA" usaremos:


SELECT CONS.TABLE_NAME, COLS.COLUMN_NAME, COMMENTS
	FROM SYS.ALL_CONSTRAINTS CONS, SYS.ALL_IND_COLUMNS COLS
	LEFT JOIN SYS.ALL_COL_COMMENTS COM ON COLS.TABLE_NAME = COM.TABLE_NAME AND COLS.COLUMN_NAME = COM.COLUMN_NAME
	WHERE COLS.INDEX_OWNER = USER AND CONS.OWNER = USER AND COM.OWNER = USER AND CONS.CONSTRAINT_TYPE = 'P' AND CONS.CONSTRAINT_NAME = COLS.INDEX_NAME AND CONS.TABLE_NAME ='NOMBRE_DE_LA_TABLA'

Para obtener la información de todos los triggers de la base de datos, incluyendo su nombre, código fuente del trigger, el evento que lo dispara, la tabla a la que esta asociado, etc:


SELECT * FROM SYS.ALL_TRIGGERS WHERE OWNER = USER 

La siguiente consulta nos devolverá todas las claves foráneas (FK's) de la tabla "NOMBRE_DE_LA_TABLA"


SELECT * FROM  SYS.ALL_CONSTRAINTS
	WHERE OWNER = USER AND TABLE_NAME ='NOMBRE_DE_LA_TABLA' AND CONSTRAINT_TYPE = 'R'

Por último la siguiente solicitud a la base de datos nos devolverá el código fuente de todos los paquetes de la base de datos, incluyendo tanto la cabecera como el cuerpo. Se devuelve un registro por cada línea del paquete.


SELECT * FROM SYS.ALL_SOURCE
	WHERE OWNER = USER AND INSTR(SYS.ALL_SOURCE.TYPE,'PACKAGE') > 0
	ORDER BY NAME, TYPE, LINE

Es importante destacar que en las consultas anteriores al filtrar por una determinada tabla su nombre debe ir en mayúsculas.

El filtro de OWNER = USER lo establecemos para obtener únicamente la información de los objetos de los que somos propietarios.

Estado del proyecto a 06/11/2006

Lunes 6 de Noviembre de 2006 a las 23:58

Desde el último post en el que hablé del estado del proyecto estos han sido los progresos que he realizado:

He creado el "motor en tiempo de ejecución" que permite procesar las instrucciones generadas por el "generador de instrucciones" a partir de las salidas de los analizadores léxico, sintáctico y semántico.

He implementado un pequeño motor gráfico o mejor dicho clase gestora de gráficos, ya que no creo que tenga la suficiente entidad como para considerarla un motor. Esta clase encapsula el acceso a las DirectX 9 proporcionando funciones de más alto nivel.

También creé unas clases para encapsular la gestión de las entradas del ratón y el teclado haciendo uso también de DirectX 9

Ahora mismo estoy trabajando en el desarrollo de diversos editores que en conjunto constituirán el editor de aventuras gráficas. Entre ellos están el editor de escenarios, el del protagonista, el de conjuntos de imágenes (tilesets), etc.

Aniversario

Domingo 5 de Noviembre de 2006 a las 23:58

Hoy 5 de Noviembre este blog cumple sus primeros cien días de existencia. Como se suele hacer en estos casos es el momento de hacer balance. Como esperaba y comente hace tiempo, el mantener este blog me esta ayudando a ser constante con el proyecto y no abandonarlo como me paso con algún proyecto anterior de dimensiones similares.

También me resulta muy gratificante compartir las experiencias, código y conocimientos con otros y pensar que probablemente a alguien le sirvan de ayuda.

Durante estos días he publicado 34 posts y he recibido 1.962 visitantes únicos que han visto 3.977 páginas.
El proyecto va avanzando lenta pero constantemente. Durante estos días el proyecto del motor de aventuras gráficas ha avanzado bastante, pero no todo lo que yo habría querido debido a la falta de tiempo. No me planteo plazos para acabarlo ya que no podrían ser realistas. La evolución del proyecto se puede ver en los sucesivos post que he publicado sobre el estado del proyecto

Nuevo sistema operativo para MSX y Amstrad

Lunes 30 de Octubre de 2006 a las 23:46

Como comenté en un post anterior hoy en día se sigue desarrollando para MSX. Y no solo juegos, sino que sorprendentemente también un sistema operativo multitarea.

Este sistema operativo se está desarrollado no solo para MSX sino también para Amstrad. El padre de la criatura es un tal Jörn Mika, el cual comenzó a desarrollarlo en el año 2000 y aunque esta muy avanzado todavía le faltan por finalizar algunos módulos.

No es simplemente un interfaz de usuario con ventanas, sino que es un sistema operativo con su propio kernel, sistema de gestión de ficheros, memoria, etc.

La página web del proyecto es la siguiente:
http://www.symbos.de/

Hay gente que además de talento tiene mucho tiempo libre :-)