Monday, 27 April 2009

Convex Hull

Convex Hull (envoltorio convexo), consiste en buscar el menor polígono convexo H por lo que cada punto X1, X2, Xn, está a un lado del polígono H o en su interior.

Existen muchas implementaciones de este sistema, pero se utiliza mucho en el reconocimiento de patrones, procesamiento de imágenes, estadística, sistemas de información geográfica, etc.

  • Diferentes implementaciones:
Podemos encontrar en la red, diversas implementaciones de los algoritmos más conocidos del Convex Hull, en diversos lenguajes de programación, Delphi, Java, C/C++, Matlab, etc. Aquí os dejo varios proyectos abiertos que intentan resolver el Convex Hull en 2D y alguno en 3D.

FastGeo 5.01
FastGeo, es una librería desarrollada en Delphi por Arash Partow. Contiene una amplia gama de algoritmos optimizados de geometría computacional y diversas rutinas para diferentes tipos de operaciones geométricas como primitivas, cálculos hull, triangulación, rotaciones, etc.
FastGeo ofrece una interfície para primitivas geométricas y rutinas complejas usando Object Pascal.

Su instalación es muy simple. Primero tenemos que descargar la librería desde este enlace: FastGeo Library Source Code, y también descargamos FastGeo Graphical Interface y FastGeo Convex Hull Demonstration. Una vez descargados, tenemos que crear un package e incluir los ficheros de la librería y de la interfície gráfica. Una vez instalado el Package, abrimos el convex Hull demonstration, y lo iniciamos. Luego podremos ver la aplicación, iniciar un test y calcular el convex Hull:


Fast Convex Hull Algorithm
Esta implementación creada en matlab, nos muestra un algoritmo muy rápido y eficiente capaz de calcular el envoltorio convexo en 2D. Esta implementación la podemos encontrar en Matlab Central de la mano de Luigi Giaccari. Podéis descargar el algoritmo directamente desde este enlace: ConvHull2D.m.

Java Convex Hull
Esta implementación sale de la Universidad de Lethbridge (Canada), de las manos del Dr. Stephen Wismath. Está hecha en un applet, y podemos crear los puntos manualmente y ver la ejecución paso a paso del algoritmo, ya sea por fuerza bruta (analizando todos los puntos) o mediante soluciones complejas de algoritmos Hull. Aquí os dejo el código fuente en descarga directa (ConvexHull.java) , echarle un vistazo ya que es muy interesante.



Algorithm 10
Esta implementación en C++ de SoftSurfer, nos provee de un cálculo sencillo mediante la entrada de unos puntos, nos devuelve la lista de puntos conectados. Este ejemplo utiliza el Andrew's monotone chain algorithm.



  • Demostraciones interactivas on-line:

http://www.cse.unsw.edu.au/~lambert/java/3d/hull.html


  • Enlaces de interés:
http://mathworld.wolfram.com/ConvexHull.html
http://www.dr-mikes-maths.com/DP-convex-hull-java-code.html

Error iniciando JBoss en Eclipse 3.4.2

Si alguna vez os encontráis con el siguiente error:



ERROR [AbstractKernelController] Error installing to Instantiated: name=TransactionManager state=Described java.lang.ExceptionInInitializerError: java.net.MalformedURLException: unknown protocol: c...


El problema puede ser que la carpeta donde está alojado el JBoss tenga algún espacio. En mi caso estaba instalado en C:\Archivos de Programa\dev\jboss-5.0.0.GA, se soluciona el problema moviendo la carpeta directamente en el directorio raíz de C -> C:\jboss-5.0.0.GA

Saturday, 25 April 2009

Implementación de persistencia de objetos en delphi mediante XML

Delphi no dispone de muchos sistemas para no decir ninguno que implemente la persistencia de Objetos como Java por ejemplo. Y como dice el pensamiento pragmático: no intentes diseccionar una rana, constrúyete tú una de nueva!. Pues allá vamos!.

Lo que he hecho, es crear las clases, y estas implementan unos métodos WriteToXML y ReadFromXML que guardan su contenido en un fichero XML. Por lo tanto cada instancia de clase, guarda todo su contenido en el fichero que se le pasa, y luego también puede recuperar todo su contenido a través de este.

Aquí os dejo un ejemplo bastante completo de mi última aplicación ThundaxSaveSeries, que permite guardar listas de series (Lost, Anatomia de Grey, 24h, Big bang, etc.) y queráis tener un pequeño registro donde indicar la temporada del capítulo, si lo habéis descargado, si lo habéis visto, etc. A mi me va bastante bien, ya que es mas portable que un excel.


En este ejemplo podéis ver como hago las llamadas a IXMLDocument, y accedo a sus nodos mediante IXMLNode.

unit Lib_Series;

interface

uses
Contnrs, SysUtils, XMLDoc, XMLIntf;

type
TEstado = (Vista, Descargada, Pendiente);

TCapitulo = class(TObject)
numero: integer;
Temporada: integer;
estado: TEstado;
constructor Create(temporada: integer; numero: integer; estado: TEstado);
function WriteToXML(XMLDoc: IXMLDocument; iXMLRootNode: IXMLNode; sNode: string): IXMLNode;
function ReadFromXML(XMLDoc: IXMLDocument; iXMLRootNode: IXMLNode): IXMLNode;
end;

TSerie = class(TObject)
Nombre: string;
NumCapitulos: integer;
CapituloInicial: integer;
temporada: integer;
TTemporada: TObjectList;
completa: boolean;
constructor Create(Nombre: string; Temporada: integer; NumCapitulos: integer; tieneCapituloZero: boolean);
function WriteToXML(XMLDoc: IXMLDocument; iXMLRootNode: IXMLNode; sNode: string): IXMLNode;
function ReadFromXML(XMLDoc: IXMLDocument; iXMLRootNode: IXMLNode; sNode: string): IXMLNode;
end;

TListaSeries = class(TObject)
ListaSeries: TObjectList;
constructor Create();
destructor Destroy(); override;
procedure WriteToXML(sArchivo: string);
procedure ReadFromXML(sArchivo: string);
end;

implementation

{ TListaSeries }

procedure TListaSeries.ReadFromXML(sArchivo: string);
var
Document: IXMLDocument;
iXMLRootNode, iXMLRootNode2: IXMLNode;
objSerie: TSerie;
begin
Document := TXMLDocument.Create(nil);
try
Document.LoadFromFile(sArchivo);
iXMLRootNode := Document.ChildNodes.First;
iXMLRootNode2 := iXMLRootNode.ChildNodes.first;
while iXMLRootNode2 <> nil do
begin
if iXMLRootNode2.NodeName = 'Serie' then
begin
objSerie := TSerie.CreateEmpty();
objSerie.ReadFromXML(Document, iXMLRootNode2, 'Serie');
Self.ListaSeries.Add(objSerie);
end;
iXMLRootNode2 := iXMLRootNode2.NextSibling;
end;
finally
Document := nil;
end;
end;

procedure TListaSeries.WriteToXML(sArchivo: string);
var
XMLDoc: TXMLDocument;
iNode, NodeSeccio: IXMLNode;
i: integer;
objSerie: TSerie;
begin
XMLDoc := TXMLDocument.Create(nil);
XMLDoc.Active := True;
iNode := XMLDoc.AddChild('TListaSeries');
for i := 0 to ListaSeries.count - 1 do
begin
NodeSeccio := iNode.AddChild('Serie');
objSerie := TSerie(ListaSeries[i]);
if objSerie <> nil then
objSerie.WriteToXML(XMLDoc, NodeSeccio, 'Serie');
end;
XMLDoc.SaveToFile(sArchivo);
end;

function TCapitulo.WriteToXML(XMLDoc: IXMLDocument; iXMLRootNode: IXMLNode; sNode: string): IXMLNode;
begin
iXMLRootNode.attributes['numero'] := IntToStr(Self.numero);
iXMLRootNode.attributes['Temporada'] := IntToStr(Self.Temporada);
iXMLRootNode.attributes['estado'] := TEstadoToStr(Self.estado);
end;

function TCapitulo.ReadFromXML(XMLDoc: IXMLDocument; iXMLRootNode: IXMLNode): IXMLNode;
begin
Self.numero := StrToInt(iXMLRootNode.attributes['numero']);
Self.Temporada := StrToInt(iXMLRootNode.attributes['Temporada']);
Self.estado := StrToTEstado(iXMLRootNode.attributes['estado']);
end;

function TSerie.WriteToXML(XMLDoc: IXMLDocument; iXMLRootNode: IXMLNode; sNode: string): IXMLNode;
var
iNodoObjeto: IXMLNode;
i: integer;
begin
iXMLRootNode.attributes['Nombre'] := Self.Nombre;
iXMLRootNode.attributes['NumCapitulos'] := IntToStr(Self.NumCapitulos);
iXMLRootNode.attributes['CapituloInicial'] := IntToStr(Self.CapituloInicial);
iXMLRootNode.attributes['temporada'] := IntToStr(Self.temporada);
iXMLRootNode.attributes['completa'] := BoolToStr(Self.completa);
for i := 0 to Self.TTemporada.Count - 1 do
begin
iNodoObjeto := iXMLRootNode.AddChild('Capitulos');
TCapitulo(Self.TTemporada.Items[i]).GuardarEnXML(XMLDoc, iNodoObjeto, 'Capitulos');
end;
end;

function TSerie.ReadFromXML(XMLDoc: IXMLDocument; iXMLRootNode: IXMLNode; sNode: string): IXMLNode;
var
iNodoObjeto, iNodoAtributo: IXMLNode;
objCapitulo: TCapitulo;
begin
iNodoObjeto := iXMLRootNode;
if iNodoObjeto.nodeName = sNode then
begin
Self.Nombre := iNodoObjeto.attributes['Nombre'];
Self.NumCapitulos := StrToInt(iNodoObjeto.attributes['NumCapitulos']);
Self.CapituloInicial := StrToInt(iNodoObjeto.attributes['CapituloInicial']);
Self.temporada := StrToInt(iNodoObjeto.attributes['temporada']);
Self.completa := StrToBool(iNodoObjeto.attributes['completa']);
iNodoAtributo := iNodoObjeto.ChildNodes.first;
while iNodoAtributo <> nil do
begin
objCapitulo := TCapitulo.CreateEmpty();
objCapitulo.ReadFromXMLDoc(XMLDoc, iNodoAtributo);
self.TTemporada.Add(objCapitulo);
iNodoAtributo := iNodoAtributo.nextSibling;
end;
end;
end;

end.








La persistencia de los objetos mediante su XML:


  • Enlaces de interés:

Podemos encontrar proyectos Open Source, que intentar hacer la persistencia de objetos para delphi, uno de estos es "Delphi Persistent Object" y lo podemos encontrar en SourceForge. Aquí os dejo el enlace directo:
http://sourceforge.net/projects/depo/

Wednesday, 22 April 2009

Añadir texto a una imagen mediante un TPaintBox y guardar el resultado en Bmp o Jpeg con Delphi 2009

Hoy me he encontrado con un pequeño problema que me ha comentado un compañero sobre coger una imagen y escribirle un texto encima automáticamente, y luego volver a guardar el resultado. La solución que propongo es bastante sencilla, y nos la podemos implementar nosotros mismos sin tener que recorrer a aplicaciones de terceros mediante unos componentes muy sencillos en Delphi 2009. La razón de hacerlo automáticamente es porque luego puede ser que la imagen provenga de una cámara y queremos guardar la fecha en que se creo dicha imagen, pero incrustandola encima de la imagen.

Un ejemplo de imagen seria el siguiente:

Lo que hago es cargar la imagen en un TPicture, y luego cargo la parte gráfica de este dentro de un TPaintBox. Mediante su canvas, puedo modificar la visualización de la imagen, y añadir texto y otras imágenes modificando sus propiedades.

Luego simplemente hago un barrido de la imagen para meterlo dentro de un TBitmap, y en el caso que quiera guardarlo en Jpeg, tengo una pequeña función que me permite hacer la conversión de Bmp a Jpeg con un pequeño fichero temporal que luego elimino. La aplicación es bastante "xorra", pero sirve para lo que quería.

Aquí os dejo parte del código, que seguro que a alguien le será de utilidad:




procedure TForm2.LoadImage();
var
c: TPicture;
s: string;
begin
c := TPicture.Create;
s := DateTimeToStr(now);
C.LoadFromFile(sfile);
PaintBox1.Canvas.Draw(0, 0, C.Graphic);
PaintBox1.Canvas.Font.Size := 20;
PaintBox1.Canvas.Font.color := clWhite;
PaintBox1.Canvas.Brush.color := clBlack;
PaintBox1.Canvas.TextOut(0, c.Height - 35, 'This image is a Box Test');
PaintBox1.Canvas.TextOut(0, c.Height - 65, s);
end;

procedure TForm2.Button2Click(Sender: TObject);
var
Bitmap: TBitmap;
Source: TRect;
Dest: TRect;
sPath: string;
i: integer;
begin
SaveDialog1.Execute(self.Handle);
for i := 0 to SaveDialog1.Files.Count - 1 do
begin
sPath := SaveDialog1.Files.Strings[i];
end;
if sPath <> '' then
begin
LoadImage();
Bitmap := TBitmap.Create;
try
with Bitmap do
begin
Width := PaintBox1.Width;
Height := PaintBox1.Height;
Dest := Rect(0, 0, Width, Height);
end;
with PaintBox1 do
Source := Rect(0, 0, Width, Height);
Bitmap.Canvas.CopyRect(Dest, PaintBox1.Canvas, Source);
Bitmap.SaveToFile(sPath);
finally
Bitmap.Free;
end;
end;
end;

function TForm2.BMPtoJPG(var BMPpic, JPGpic: string): boolean;
var
Bitmap: TBitmap;
JpegImg: TJpegImage;
begin
Result := False;
Bitmap := TBitmap.Create;
try
Bitmap.LoadFromFile(BMPpic);
JpegImg := TJpegImage.Create;
try
JpegImg.Assign(Bitmap);
JpegImg.SaveToFile(JPGpic);
Result := True;
finally
JpegImg.Free
end;
finally
Bitmap.Free
end;
end;





Además os dejo también la aplicación que he generado: ThundaxWriteImage.exe

Tuesday, 21 April 2009

El modelo Dreyfus sobre la adquisición de competencias

Estoy acabando de leer el libro Pragmatic Learning and Thinking: Refactor your wetware, y la verdad es que cuanto más lo leo, más ideas vienen a mi mente, porqué además de aprender cosas nuevas, entiendo mejor el funcionamiento de nuestro cerebro y te da un guión bastante bueno de como mejorar y llegar a ser un experto en el campo donde trabajes. Estos conceptos son bastante novedosos para mi, gracias al autor Andy Hunt. Aunque internamente estos conceptos ya los tenia asimilados, por fin hay alguien que los ha exteriorizado mediante un libro. En cuanto leí el segundo capítulo que hablaba del modelo Dreyfus sobre la adquisición de competencias, un montón de cosas empezaban a tener sentido para mí desde el punto de vista del análisis y la programación.

El modelo Dreyfus fue creado por Huber Dreyfus un profesor de filosofía en la Universidad de California (Berkeley). En la década de los 80, publicó el documento sobre las etapas de adquisición de competencias. Estas etapas son: novato, principiante avanzado, competente, profesional y experto. Estas etapas son las conocidas como modelo Dreyfus sobre la adquisición de competencias.

Este modelo o estudio, muestra el desarrollo de novato a experto en diferentes profesiones, como enfermeras, jugadores de ajedrez o operadores. Y muestra como hacer el paso de un estado a otro, mediante el aprendizaje y la práctica.

Una visión interesante del modelo Dreyfus, es que en la etapa de novato, las personas necesitan unas reglas, los principiantes, están preocupados por su capacidad para triunfar y que no tienen mucha experiencia. Estos, no están muy interesados en el aprendizaje, sino que desean logran un objetivo inmediato, y son más eficaces cuando se les da la instrucción precisa de cómo actuar.

Cuando miro hacia atrás en mi progresión, puedo ver las características exactas que se definen en el modelo Dreyfus, y puedo ubicarme en la etapa que más me corresponde.

Los competentes, pueden desarrollar modelos conceptuales del problema principal y trabajar sobre este modelo de manera eficiente. Pueden resolver problemas por su cuenta, y pueden comenzar a aplicar consejos de los expertos y usarlos correctamente. Pero aún no son capaces de aplicar metodologías ágiles.

Los Profesionales están en una etapa muy avanzada, no se conforman con la poca información que se les da en un proyecto, y tienen una visión más global. Son personas que pueden aprender de la experiencia de otras, aprender de sus errores y mejorar. Comprueban y testean todos los sistemas que crean, y además saben muy bien por donde pueden romperse. Los Profesionales, pueden tomar ventaja sobre la reflexión y el feedback, y esto es el núcleo de las metodologías ágiles.

Finalmente, el Experto. Estos son la fuente de información en cualquier campo del conocimiento. Normalmente escriben libros, artículos, etc. y no hay muchos de ellos, entre el 1% y el 5% de la población. Los expertos trabajan desde la intuición no desde la razón. Algunas investigaciones demuestran que se necesitan por lo menos 10 años de estudio para convertirse en un experto , otros dicen que se necesitan 10.000 horas de práctica.

Aquí os dejo un pequeño diagrama que muestra las 5 etapas del modelo Dreyfus:

Espero que os animéis a leer el libro, ya que a través del pensamiento pragmático y las metodologías ágiles, podemos mejorar, y subir un escalón más del modelo hasta convertirnos en expertos!.

Aquí os dejo otra imagen, que muestra un resumen del modelo, la he sacado de The Clean Collection:


  • Más información:
http://pragmaticstudio.com/dreyfus


Saturday, 18 April 2009

Mantenerse al día!

Bueno, últimamente he tenido bastante tiempo para leer, y creo que es muy importante mantenerse al día sobre las nuevas tecnologías y conceptos que van apareciendo, ya que un buen desarrollador tiene que ir evolucionando y adquiriendo nuevas habilidades de trabajo. El pensamiento pragmático es uno de los que más me ha cautivado, y hace tiempo que leo los libros del Pragmatic Programming. Mis últimas adquisiciones son las siguientes, y que creo que algún día si podéis, si tenéis esa curiosidad por saber, tendríais que leer. Son "da bomb".

Podéis encontrar la lista completa en Pragmatic BookShelf, y podéis encontrarlos a muy buen precio por amazon (de segunda mano claro!), pero cada libro no suele tener más de 200 páginas, por lo tanto son bastante rápidos de leer, el problema es aplicar y entender bien el concepto que quiere transmitirte el autor. Pero para mi, han sido un gran descubrimiento. Ahora estoy acabando de leer el libro sobre el wetware (Pragmatic thinking and learning), seguramente cuando lo acabe escribiré un post sobre esto, porqué es muy interesante, es un libro bastante novedoso del 2008, y habla sobre el concepto de la mejora de tus aplicaciones sabiendo utilizar mejor tu cerebro...da bomb!.

Friday, 17 April 2009

Que es Peaberry?

Peaberry, es una extensión de la librería para Google Guice que soporta inyección de dependencia para servicios dinámicos. Provee integración OSGi, y para otros plug-ins basados en servicios de registro. Mediante esta extensión, podemos recoger los Bundles del OSGi, i transformarlos a módulos OSGi que entiende la plataforma del Dependency Injection (Google Guice). Si analizamos el ejemplo disponible desde la misma web del proyecto Peaberry en Google Code, ScramblerTest, podemos probarlo para ver como funciona, y en el apartado de documentación podemos encontrar un poco de información de las librerías y de su implementación:

"org.ops4j.peaberry.Peaberry" construye el proveedor de servicios.

"org.ops4j.peaberry.util" contiene ayudas opcionales para las clases.

Inyectando a un Servicio Dinámico desde OSGi:

@Inject
LogService logService;
...
bind(LogService.class).to(service(LogService.class).single());

Exportando una implementación como un servicio OSGi:

@Inject
Export exportedLogService;
...
bind(export(LogService.class)).to(registration(logImplKey).export());

Podemos encontrar más ejemplos en el javadoc del Peaberry.

Dependency Injection - da bomb!

Inyección de Dependencias (DI) es un patrón de arquitectura orientado a objetos, en el que se inyectan objetos a una clase en lugar de ser la propia clase quien cree el objeto. Todo este concepto está muy bien explicado en el libro del Google Guice: Agile Lightweight Dependency Injection Framework, donde aparecen varios ejemplos de inyección y las descripciones de todo este palabreo friki como "framework" o "Inversion of Control IoC". Es este post encontrareis un buen ejemplo y simple sobre el uso de la inyección de dependencias, que además he combinado con el Chaining Method para darle más "jugo". Este ejemplo, se basa en un constructor de edificios (BuilderConstructor), que tiene que construir una casa, con un par de ventanas y una puerta. El ejemplo es básico, y mediante proveedores de casas, puertas y ventanas, le daremos las herramientas necesarias para que el constructor de edificios pueda crear la casa sin problemas.

El ejemplo en UML es el siguiente:

Disponemos de la clase House, Window i Door. La casa puede contener Windows y Doors, y estas pueden tener el tamaño que queramos.

En el BuilderConstructor, se inyectan los proveedores de House, Door y Window. El BuilderModule, es el que hace referencia y enlaza los proveedores con las diferentes clases, por lo tanto el Proveedor de puertas está enlazado con la clase Door y así con las demás clases.

Con el BuilderTest, crearemos la aplicación y las dependencias (Inyectores) con guice para que nuestro constructor pueda construir la casa.

La implementación del Provider, simplemente es una pequeña factoría de clase que Guice invocará cuando necesite una instancia de ese tipo.

  • Ejemplo de inyección @Inject:
House.java



import java.util.*;

public class House {
private ArrayList<Window> windows = new ArrayList<Window>();
private ArrayList<Door> doors = new ArrayList<Door>();

public House addWindow(Window window) {
this.windows.add(window);
return this;
}

public House addDoor(Door door) {
this.doors.add(door);
return this;
}

public String Description() {
String text;
text = "This is a house with " + windows.size() + " Windows and \n";
text = text + doors.size() + " Doors, the Windows are: \n";
Iterator<Window> winIterator = windows.iterator();
while (winIterator.hasNext()) {
text = text + (" " + winIterator.next().size() + " \n");
}
text = text + "and the Doors are \n";
Iterator<Door> doorIterator = doors.iterator();
while (doorIterator.hasNext()) {
text = text + (" " + doorIterator.next().size() + " \n");
}
return text;
}
}




Window.java



public class Window {
private int width;
private int height;

public Window(int width, int height) {
setWidth(width);
setHeigth(height);
}

public String size() {
return "Size " + height + "x" + width;
}

public void setWidth(int width) {
this.width = width;
}

public int getWidth() {
return width;
}

public void setHeigth(int height) {
this.height = height;
}

public int getHeigth() {
return height;
}
}




Door.java



public class Door {
private int width;
private int height;

public Door(int width, int height) {
setWidth(width);
setHeigth(height);
}

public String size() {
return "Size " + height + "x" + width;
}

public void setWidth(int width) {
this.width = width;
}

public int getWidth() {
return width;
}

public void setHeigth(int height) {
this.height = height;
}

public int getHeigth() {
return height;
}
}




HouseProvider.java, WindowProvider.java and DoorProvider.java



import com.google.inject.Provider;

public class HouseProvider implements Provider<House> {
public House get() {
return new House();
}
}

import com.google.inject.Provider;

public class WindowProvider implements Provider<Window> {
public Window get() {
return new Window(10, 10);
}
}


import com.google.inject.Provider;

public class DoorProvider implements Provider<Door> {
public Door get() {
return new Door(30, 10);
}
}




BuilderModule.java



import com.google.inject.AbstractModule;

public class BuilderModule extends AbstractModule {
protected void configure() {
bind(Window.class).toProvider(WindowProvider.class);
bind(Door.class).toProvider(DoorProvider.class);
bind(House.class).toProvider(HouseProvider.class);
}
}




BuilderConstructor.java



import com.google.inject.Inject;
import com.google.inject.Provider;

public class BuilderConstructor {
@Inject
private Provider<House> houseProvider;
@Inject
private Provider<Door> doorProvider;
@Inject
private Provider<Window> windowProvider;

public House getHouse() {
return houseProvider.get();
}

public Door getDoor() {
return doorProvider.get();
}

public Window getWindow() {
return windowProvider.get();
}
}




BuilderTest.java



import com.google.inject.Guice;
import com.google.inject.Injector;

public class BuilderTest {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new BuilderModule());
BuilderConstructor m = injector.getInstance(BuilderConstructor.class);
House house = m.getHouse();
house.addDoor(m.getDoor()).addWindow(m.getWindow())
.addWindow(m.getWindow());
System.out.println(house.Description());
}
}




El resultado de ejecutar esta aplicación es el siguiente:

This is a house with 2 Windows and
1 Doors, the Windows are:
Size 10x10
Size 10x10
and the Doors are
Size 10x30

Por lo tanto, aquí tenemos nuestra aplicación con inyección. En el BuilderConstructor, se añaden los @Inject en las variables de tipo Provider, y estas se crear automáticamente cuando se hace la inyección.

De todas maneras, esto es solo la punta del iceberg, hay muchas más opciones para aprender dentro del tema del DI. Dependency Injection minimiza la complejidad a través de la abstracción, y permite que tengamos una aplicación más modular y nos permite hacer el testing de una manera más fácil.

  • Enlaces de interés:
http://lebensold.net/category/php
http://misko.hevery.com/2008/07/08/how-to-think-about-the-new-operator/
http://martinfowler.com/articles/injection.html