Wednesday, 19 August 2009

Implementando un Abstract Factory

Continuando con mi aplicación Thundax Geometry Link, necesito implementar un patrón Abstract Factory. Mediante éste patrón crearé diferentes familias sin especificar su clase concreta. Éste patrón es ideal cuando queremos aislar nuestra aplicación de la implementación de clases concretas. En el siguiente ejemplo podréis ver como genero la TAbstractFactory, que es la que me permitirá poder crear los objetos que yo quiero, una TBox, una TConnector y una TEllipse, pero que éstas haré que deriven de la TAbstractBox, TAbstractConnector y TAbstractEllipse, porqué quiero poder implementar varias familias por debajo de TAbstractBox sin que la factoría tenga que saberlo. Luego crearé 2 factorías, una simple y una extendida, donde configuraré la creación de mis clases. De ésta manera, en cada constructor de la factoría especificamos el objeto a devolver, sin especificar la clase concreta. En los ejemplos lo veréis más claro.

El diagrama UML de mi ejemplo es el siguiente (Esquematizado):

Como podéis comprobar, antes solo existía la clase TBox, y ahora el diseño ha cambiado un poco. Ahora dispongo de mi TAbstractBox de la cuál hago heredar para conseguir diversos tipos de caja, en éste caso la TBox genérica y la TBoxExtended, la cuál dispondrá de más opciones y propiedades. Lo mismo pasa con las 2 otras clases. Pensad que el diseño de la aplicación va cambiado día a día y que ésto puede no ser algo definitivo.

Bien, ahora para el diseño de la factoría tenemos:

Como podéis comprobar, las 2 factorías devuelven el mismo tipo de componente, pero en cada una se definen clases diferentes, aquí la poténcia de la Abstract Factory.

Mi diagrama vendría a ser algo parecido, en el diagrama UML de ejemplo que hay en la web de A&P Web Consulting:


Queda bastante detallado en el diagrama, y en la wikipedia también encontraréis más información. Mirad también en los enlaces de interés, que he dejado también algún link.

El código fuente del ejemplo es el siguiente:

TAbstractBox, TAbstractConnector y TAbstractEllipse:

type
    TAbstractBox = class(TObject)
        function ToString(): string; virtual; abstract;
    end;

    TBox = class(TAbstractBox)
        function ToString(): string; override;
    end;

    TBoxExtended = class(TAbstractBox)
        function ToString(): string; override;
    end;

    TAbstractConnector = class(TObject)
        function ToString(): string; virtual; abstract;
    end;

    TConnector = class(TAbstractConnector)
        function ToString(): string; override;
    end;

    TConnectorExtended = class(TAbstractConnector)
        function ToString(): string; override;
    end;

    TAbstractEllipse = class(TObject)
        function ToString(): string; virtual; abstract;
    end;

    TEllipse = class(TAbstractEllipse)
        function ToString(): string; override;
    end;

    TEllipseExtended = class(TAbstractEllipse)
        function ToString(): string; override;
    end;
  

{ TBox }

function TBox.ToString: string;
begin
    result := 'This is a ' + Self.ClassName;
end;

{ TConnector }

function TConnector.ToString: string;
begin
    result := 'This is a ' + Self.ClassName;
end;

{ TEllipse }

function TEllipse.ToString: string;
begin
    result := 'This is a ' + Self.ClassName;
end;

{ TEllipseExtended }

function TEllipseExtended.ToString: string;
begin
    result := 'This is a ' + Self.ClassName;
end;

{ TConnectorExtended }

function TConnectorExtended.ToString: string;
begin
    result := 'This is a ' + Self.ClassName;
end;

{ TBoxExtended }

function TBoxExtended.ToString: string;
begin
    result := 'This is a ' + Self.ClassName;
end;  

TAbstractFactory, TMySimpleFactory y TMyExtendedFactory:

type
    TAbstractFactory = class(TObject)
    public
        constructor Create;
        destructor Destroy; override;
        function GetBox(): TAbstractBox; virtual; abstract;
        function GetConnector(): TAbstractConnector; virtual; abstract;
        function GetEllipse(): TAbstractEllipse; virtual; abstract;
    end;

    TMySimpleFactory = class(TAbstractFactory)
    public
        constructor Create;
        destructor Destroy; override;
        function GetBox(): TAbstractBox; override;
        function GetConnector(): TAbstractConnector; override;
        function GetEllipse(): TAbstractEllipse; override;
    end;

    TMyExtendedFactory = class(TAbstractFactory)
    public
        constructor Create;
        destructor Destroy; override;
        function GetBox(): TAbstractBox; override;
        function GetConnector(): TAbstractConnector; override;
        function GetEllipse(): TAbstractEllipse; override;
    end;

{ TAbstractFactory }

constructor TAbstractFactory.Create;
begin

end;

destructor TAbstractFactory.Destroy;
begin

    inherited;
end;

{ TMySimpleFactory }

constructor TMySimpleFactory.Create;
begin

end;

destructor TMySimpleFactory.Destroy;
begin

    inherited;
end;

function TMySimpleFactory.GetBox: TAbstractBox;
begin
    result := TBox.Create;
end;

function TMySimpleFactory.GetConnector: TAbstractConnector;
begin
    result := TConnector.Create;
end;

function TMySimpleFactory.GetEllipse: TAbstractEllipse;
begin
    result := TEllipse.Create;
end;

{ TMyExtendedFactory }

constructor TMyExtendedFactory.Create;
begin

end;

destructor TMyExtendedFactory.Destroy;
begin

    inherited;
end;

function TMyExtendedFactory.GetBox: TAbstractBox;
begin
    result := TBoxExtended.Create;
end;

function TMyExtendedFactory.GetConnector: TAbstractConnector;
begin
    result := TConnectorExtended.Create;
end;

function TMyExtendedFactory.GetEllipse: TAbstractEllipse;
begin
    result := TEllipseExtended.Create;
end;

Ejemplo de utilización:

procedure TForm1.Button1Click(Sender: TObject);
begin
    Factory := TMySimpleFactory.Create;
    Memo1.Lines.add(Factory.GetBox.ToString);
    Memo1.Lines.add(Factory.GetConnector.ToString);
    Memo1.Lines.add(Factory.GetEllipse.ToString);

    FactoryExtended := TMyExtendedFactory.Create;
    Memo1.Lines.add(FactoryExtended.GetBox.ToString);
    Memo1.Lines.add(FactoryExtended.GetConnector.ToString);
    Memo1.Lines.add(FactoryExtended.GetEllipse.ToString);
end;

Como resultado del ejemplo obtendremos:


  • Enlaces de interés:
Abstract Factory in Delphi.

0 comments:

Post a Comment