Abstract Factory (Fábrica Abstracta) é un padrón de deseño para o desenvolvemento de software.

O padrón de fábrica abstracta (abstract factory pattern) é un padrón de deseño de software que nos ofrece unha forma de encapsular un grupo de fábricas individuais que teñen un tema común. No seu uso normal, o cliente de software crea unha posta en funcionamento concreta da fábrica abstracta e logo usa as interfaces xenéricas para crear obxectos concretos que son parte do tema. O cliente non sabe nin lle importan os obxectos concretos que obtén de cada unha destas factorías internas xa que só usa as interfaces xenéricas dos seus produtos.

Este padrón separa os detalles de posta en funcionamento dun conxunto de obxectos do seu uso xeral.

Unha factoría é o lugar ou a clase concreta no código onde os obxectos son construídos. A idea ó usar o padrón é illar a creación dos obxectos do seu uso. Isto da liberdade para crear novos tipos derivados sen ningún cambio no código que utiliza a clase base.

O uso deste padrón fai posible intercambiar postas en funcionamento concretas sen cambiar o código que as usa, incluso en tempo de execución. De tódolos xeitos, o uso deste padrón, así coma con padróns similares, pode resultar unha complexidade innecesaria e un traballo extra para a escritura do código inicial. Usado correctamente, este traballo extra na escritura inicial acelera moito a seguinte posta en funcionamento da factoría.

Definición

editar

A idea detrás deste padrón de deseño é a de crear familias de obxectos relacionados ou dependentes entre si sen especificar as súas clases concretas.

A factoría determina o tipo concreto do obxecto a crear, así coma a propia creación deste. De tódolos xeitos, só devolve un punteiro abstracto ó obxecto concreto creado.

Isto illa o código cliente da creación do obxecto, tendo clientes que pidan a un obxecto fábrica crear un obxecto do tipo abstracto desexado e retornando un punteiro abstracto ó obxecto.

Como a factoría só devolve un punteiro abstracto, o código cliente non sabe, e polo tanto non é dependente do tipo concreto real do obxecto que se acaba de crear. De tódolos xeitos o tipo do obxecto concreto, e polo tanto, a factoría concreta, é coñecido pola factoría abstracta. Por exemplo, a factoría pode lelo dun ficheiro de configuración. O cliente non ten porqué especifica-lo tipo xa que foi especificado no ficheiro de configuración, o que significa:

  • O código do cliente non ten coñecemento do tipo concreto, non ten que incluír ficheiros de cabeceira nin declaración de clase relativos ao tipo concreto. Obxectos dun tipo concreto son creados pola factoría pero só son accesibles pola interface abstracta.
  • Pódense engadir novos tipos concretos modificando o código cliente para utilizar unha factoría diferente, para o que só se necesita modificar unha liña nun arquivo. Ambas factorías crearán diferentes obxectos, pero baixo o mesmo tipo abstracto, polo que se illa o código do cliente do cambio. Isto é moito máis fácil que modificar o código cliente para instanciar un novo tipo, o que requiriría cambiar cada lugar no código onde se crea un novo obxecto (ademais de que en cada lugar se debe de comprobar que existe coñecemento da nova clase). Se tódolos obxectos da factoría están gardados globalmente nun obxecto singleton e todo o código cliente vai a través do singleton para acceder á creación do obxecto e logo cambia-las factorías é tan doado coma cambiar o obxecto singleton.

Exemplo

editar

Diagrama de clases

editar

 

/* GUIFactory example -- */

#include<iostream>
using namespace std;

class Button {
public:
	virtual void paint() = 0;
        virtual ~Button(){
        }
};

class WinButton: public Button {
public:
	void paint() {
		cout << "I'm a WinButton";
	}
};

class OSXButton: public Button {
public:
	void paint() {
		cout << "I'm an OSXButton";
	}
};

class GUIFactory {
public:
	virtual Button * createButton() = 0;
        virtual ~GUIFactory(){
        }
};

class WinFactory: public GUIFactory {
public:
	Button * createButton() {
		return new WinButton();
	}

        ~WinFactory(){
        }
};

class OSXFactory: public GUIFactory {
public:
	Button * createButton() {
		return new OSXButton();
	}
         
        ~OSXFactory(){
        }
};

class Application {
public:
	Application(GUIFactory * factory) {
		Button * button = factory->createButton();
		button->paint();
                delete button;
                delete factory;
	}
};

GUIFactory * createOsSpecificFactory() {
	int sys;
	cout << endl << "Enter OS Type(0 - Win, 1 - OSX): ";
	cin >> sys;

	if (sys == 0) {
		return new WinFactory();
	} else {
		return new OSXFactory();
	}
}

int main(int argc, char **argv) {
	Application * newApplication = new Application(createOsSpecificFactory());
	delete newApplication;
	return 0;
}