After seeing 1000 ctors

I heard it a lot of times. When I was learning Java, a flash definition about constructor methods faded away in the classroom. A “silly” definition that nobody seemed to remember a bunch of years later.

Sometimes the things that are easily forgotten are the most basic principles. We take them as a fact and we rarely reevaluate them.

One of the basics in OOP is the role of a constructor method:

A constructor method is a special method that contains ONLY the required initializations for the instance to be created in a valid state, ready to be used.

Said this, any constructor what invokes complex methods, services to retrieve data, contains lots of lines of code, or even loops, IS A MISTAKE and needs to be fixed.

A constructor has to be minimum! The instance should be created just in time and any complex initialization should be the responsibility of any other method of the instance.

This answer on Stack Overflow is very good. Be sure to read it 🙂 and keep you ctors clean!

http://stackoverflow.com/questions/1183531/how-much-work-should-the-constructor-for-an-html-parsing-class-do

Anuncios

Otra de ViewModels (con Cinch)

Señores, la peña está aburrida de escucharme insistir en cosas como SOLID, DDD, Separation Of Concerns, MVVM, XAML y demás.

Pero copón bendito, ¡si es que llevo razón! Dejad de hacer ñapas y programad como hombres, ¡joder!

Pues después de este arrebato para aquellos que más que programan “tirar líneas” y no aspiran a hacerlo mejor, os digo: el modelo es el camino , la verdad y la vida..

Para ello os propongo el siguiente caso extravagante. Queremos construir una instancia de nuestro modelo mediante un “asistente”. La interfaz da una serie de opciones para controlar sus propiedades. Hasta aquí todo es normal, pero ahora llega lo novedoso: nuestro modelo es un control visual. ¡Imaginad un botón! Queremos establecer sus propiedades con el asistente y el usuario puede ir controlando, por ejemplo, el tamaño del borde, el color de fondo, su texto…

Bien, nosotros queremos que cuando el usuario vaya introduciendo modificaciones en el control, se vaya actualizando su apariencia.

La cosa seguramente más de alguno todo esto lo haría a base de eventos y “sin complicarse” la vida, pero si quieres ser un maestro de la abstracción puedes optar por hacerlo como yo, un dopao de MVVM con 0% de materia grasa.

¿Qué he hecho? He creado la ventanita y un ViewModel que se hacer cargo de todas las propiedades del modelo (un Botón hecho a medida). Pero ahora viene lo divertido. Como no me gusta andar descalzo, voy armado con el Framework MVVM del maestro Sacha Barber, un tipo prático donde los haya, pero con un gusto por la elegancia y por la pureza.

Ese peaso de framework tiene durezas a chorros, pero una de las que más encandilan son las relacionadas con las validaciones. Te recomiendo que te pongas a mirarte Cinch si quieres hacer algo decente con MVVM y que prestes atención a los DataWrappers.

Básicamente un DataWrapper (envoltorio de datos) es eso, un envoltorio que se ocupa de encapsular una propiedad del ViewModel y proporcionarle soporte para validación y/o edición.

El tema es que esos DataWrappers contienen un DataValue con el dato encapsulado. Es posible agregar reglas al DataWrapper para que el ViewModel padre se entere de si se encuentran en un estado válido o no. La vista reaccionara a las validaciones sin tener que realizar actualizaciones. Todo perfectamente controlado y muy declarativo.

Bueno, para enteraros del tema no hay nada mejor que los tutoriales que pone Sacha en The Code Project. Por ejemplo: http://www.codeproject.com/Articles/38672/WPF-If-Carlsberg-did-MVVM-Frameworks-Part-4-of-n

¿Y para qué quiero Cinch y los DataWrappers del demonio?

Pues la verdad es que es muy jodido de explicar, pero en esencia resulta que el usuario puede meter cualquier dato y puede que ese dato no sea correcto. Imaginad el borde del botón. Le ponemos 1.000.000 de píxeles de ancho y la previsualización, evidentemente, pegaría un flete enorme al renderizar semejante barbarie.

La idea es que cuando el dato no sea válido, la previsualización PASA OLÍMPICAMENTE del dato.

¿Cómo? Con disparadores en el XAML, concretamente un estilo con DataTriggers 😉

Y ahora, para quien quiera saber la solución final, aquí está la pregunta que hice en Stack Overflow al respecto, que detalla todo el lío en inglés, que incluye la solución, con un trocete de XAML por si queda alguna duda.

http://stackoverflow.com/questions/17675285/mvvm-make-binding-update-viewmodel-only-when-data-is-valid/17695186?noredirect=1#17695186

Finalmente, si has llegado a leer hasta aquí y no te ha dado una embolia cerebral, o no te has dormido de aburrimiento, o si aún no piensas que se me va muchísimo la olla, quiero felicitarte sinceramente. ¡OLÉ TUS HUEVOS!

ViewModels: make them right!

It’s not so simple to just make a class implement the INotifyPropertyChanged and create some properties.

Normally you have to REPRESENT a model. But how? Replicating the properties in the model that you want? Exposing the model itself using a property?

That is a good question that every MVVM lover should have asked himself when writhing a ViewModel.

You can take a look at this article. It really hits the nail on the head.

http://msdn.microsoft.com/en-us/magazine/ff798279.aspx

I normally expose the model directly and make UI classes that implement INotifyPropertyChanged. But I see the property mapping far more elegant and pure MVVMish 😉

What do you prefer?

Tentaciones: llamar a this() y base() al mismo tiempo

Como estás muy loco, a veces se te pasa por la cabeza hacer historias descabelladas. Llamar a this() y a base() no se puede, jodío. Aquí lo que tienes que hacer es diseñar los constructores como es debido, no a ciegas, ¡que vas ciego por la vida!

Ejemplo. Tienes una clase Base y otra Derivada.

La clase Derivada tiene un constructor de copia que se basa en un argumento para hacer la copia:

public Derivada(Base toCopyFrom) : base(toCopyFrom)
{
}

Le proporcionamos un objeto del que copiar propiedades. El objeto se lo pasamos a la Base y esta se encarga del resto.

Ahora echamos un ojo al constructor por defecto:

public DynamicTable()
{
	atributoQueNecesitaInicialización = "bla bla bla";
	otroAtributoQueNecesitaInicialización = "bla bla bla";
}

¿Qué ocurre? que si esos atributos necesitan inicializarse, solamente se inicializan llamando al constructor por defecto.

En otro constructor que llama a la base (el de más arriba), los atributos no se inicializan. Puede que tengamos la tentación de modificar el constructor que llama a la base y añadirle esto:

public Derivada(Base toCopyFrom) : base(toCopyFrom), this()
{
}

Pero ¡DÓNDE VAS, LOCO! Eso no puede hacerse y es por una buena razón Pointing up El orden se establece arbitrariamente (primero base, luego this), por lo que si el compilador nos dejara hacer esto, sería una porquerida. Así es que pensamos ¿y si copio las líneas que inicializan las variables también en el otro constructor?

GUARRADA X2!! ¿Duplicar? Chaval, ¡eso es el principio del fin! Nada de duplicar, ¡cojones ya!

Como no somos unos guarretes, decidimos solucionar la papeleta con el estoque fino.

Sencillo, o no tanto:

El constructor por defecto debe llamar al específico con el objeto a null, por ejemplo:

public Derivada() : this(null)
{
}

Aunque lo de meter un null no es una práctica bella (ni aconsejable) lo pongo para que se entienda el concepto. Luego podemos aplicar el patrón NullObject y hacer las comprobaciones necesarias si se trata de ese caso).

De esta manera, el constructor por defecto llama al específico con un null. Finalmente, este constructor específico SÍ llama a la base. Pero además, en él será donde debemos inicializar las variables que teníamos antes. Por lo tanto quedaría así.

public Derivada(Base toCopyFrom) : base(toCopyFrom)
{
	atributoQueNecesitaInicialización = "bla bla bla";
	otroAtributoQueNecesitaInicialización = "bla bla bla";
}

Así, la clase Base construye la copia (le pasamos un nulazo enorme que en estos momento actuaría de indicador. La clase base en este caso debería saber que un null significa un caso especial. Si estamos copiando atributos (constructor de copia) lo más lógico es que no copiara nada.

Si a alguien se le ocurre algo mejor, ¡ahí están los comentarios, muertos de risa! Thinking smile