« Patrons de conception/Fabrique abstraite » : différence entre les versions
Contenu supprimé Contenu ajouté
m 51 versions depuis w:Fabrique abstraite (patron de conception) : Patrons de conception/Fabrique abstraite |
+ |
||
Ligne 1 :
{{Patrons de conception}}
Une fabrique abstraite encapsule un groupe de [[../Fabrique
Le code client crée une implémentation concrète de la fabrique abstraite, puis utilise les interfaces génériques pour créer des objets concrets de la thématique. Le client ne se préoccupe pas de savoir laquelle de ces fabriques a donné un objet concret, car il n'utilise que les interfaces génériques des objets produits. Ce patron de conception sépare les détails d'implémentation d'un ensemble d'objets de leur usage générique. Un exemple de fabrique abstraite : la classe ''documentCreator'' fournit une interface permettant de créer différents produits (e.g. ''createLetter()'' et ''createResume()''). Le système a, à sa disposition, des versions concrètes dérivées de la classe ''documentCreator'', comme par exemple ''fancyDocumentCreator'' et ''modernDocumentCreator'', qui possèdent chacune leur propre implémentation de ''createLetter()'' et ''createResume()'' pouvant créer des objets tels que ''fancyLetter'' ou ''modernResume''. Chacun de ces produits dérive d'une [[classe abstraite]] simple comme ''Letter'' ou ''Resume'', connues du client. Le code client obtient une instance de ''documentCreator'' qui correspond à sa demande, puis appelle ses méthodes de fabrication. Tous les objets sont créés par une implémentation de la classe commune ''documentCreator'' et ont donc la même thématique (ici, ils seront tous ''fancy'' ou ''modern''). Le client a seulement besoin de savoir manipuler les classes abstraites ''Letter'' ou ''Resume'', et non chaque version particulière obtenue de la fabrique concrète.
Ligne 10 ⟶ 13 :
== Utilisation ==
La ''fabrique'' détermine le type de l'
Le code client est ainsi isolé de la création de l'objet en l'obligeant à demander à une fabrique de créer l'objet du type abstrait désiré et de lui en retourner le pointeur.
Comme la fabrique retourne uniquement un pointeur abstrait, le code client qui sollicite la fabrique ne connaît pas et n'a pas besoin de connaître le type concret précis de l'objet qui vient d'être créé. Cela signifie en particulier que :
* Le code client n'a aucune connaissance du type concret, et ne nécessite donc aucun fichier
* L'ajout de nouveaux types concrets dans le code client se fait en spécifiant l'utilisation d'une fabrique différente, modification qui concerne typiquement une seule ligne de code (une nouvelle fabrique crée des objets de types concrets ''différents'', mais renvoie un pointeur du ''même'' type abstrait, évitant ainsi de modifier le code client). C'est beaucoup plus simple que de modifier chaque création de l'objet dans le code client. Si toutes les fabriques sont stockées de manière globale dans un [[singleton (patron de conception)|singleton]] et que tout le code client utilise ce singleton pour accéder aux fabriques pour la création d'objets, alors modifier les fabriques revient simplement à modifier l'objet singleton.
== Diagramme de classes UML ==
Le patron de conception Fabrique Abstraite peut être représenté par le diagramme UML de classes suivant :
[[Fichier:UML DP Fabrique abstraite.png|center|Diagramme UML
== Exemples ==
Ligne 27 ⟶ 30 :
<source lang="cpp">
struct Button
{ virtual void paint() = 0;
};
struct WinButton : public Button
{ void paint
{
std::cout << " I'm a window button \n";
}
};
struct OSXButton : public Button
{ void paint
{
std::cout << " I'm a OSX button \n";
}
};
struct GUIFactory
{ virtual Button* createButton
};
struct WinGUIFactory : public GUIFactory
{ Button* createButton
{
return new WinButton(); }
};
struct OSXGUIFactory : public GUIFactory
{ Button* createButton
{
return new OSXButton(); }
};
struct Application
{ Application(GUIFactory* factory)
{
Button* button = factory->createButton();
button->paint();
}
};
/* application : */
int main()
{
GUIFactory* factory1 = new WinGUIFactory();
GUIFactory* factory2 = new OSXGUIFactory();
Application* winApp = new Application (factory1);
Application* osxApp = new Application (factory2);
delete factory1, factory2;
return 0;
}
</source>
Ligne 88 ⟶ 102 :
<source lang="csharp">
/*
* Exemple : GUIFactory
*/
abstract class GUIFactory
{
{
int
if (sys==0)
return(new WinFactory()); }
public abstract Button createButton();
{ {
return(new WinButton()); { {
return(new OSXButton()); { { {
Console.WriteLine("I'm a WinButton: "+caption);
{ {
Console.WriteLine("I'm a OSXButton: "+caption);
{ {
GUIFactory
Button aButton
// I'm a WinButton: Play
// ou :
// I'm a OSXButton: Play </source>
Ligne 149 ⟶ 175 :
<source lang="java">
* GUIFactory example
*/
public abstract class GUIFactory
{
public static GUIFactory getFactory()
{
int
if (sys == 0)
return(new WinFactory()); }
public abstract Button createButton();
{ {
return(new WinButton()); { {
return(new OSXButton()); { {
return caption; public void
this.caption = caption;
}
}
{ {
System.out.println("I'm a WinButton: "+ getCaption());
{ {
System.out.println("I'm a OSXButton: "+ getCaption());
{ {
GUIFactory
Button aButton = aFactory.
// I'm a WinButton: Play
// ou :
// I'm a OSXButton: Play </source>
Ligne 218 ⟶ 258 :
<source lang="perl">
sub new {
bless({}, shift);
}
sub createButton {
return(GtkButton->new);
}
package TkFactory;
use base 'GUIFactory';
sub new {
bless({}, shift);
}
sub createButton() {
return(TkButton->new);
}
package Button;
sub new {
$class = shift;
my $self = {};
$self{caption} = '';
bless($self, $class);
return $self;
}
package GtkButton;
use base 'Button';
sub paint() {
print "I'm a GtkButton\n";
}
package TkButton;
use base 'Button';
sub paint() {
print "I'm a TkButton\n";
}
package main;
my $aFactory = GUIFactory->getFactory;
my $aButton = $aFactory->createButton;
$aButton->{caption} = "Play";
$aButton->paint();
</source>
Ligne 303 ⟶ 343 :
public abstract function createButton();
}
class WinFactory extends GUIFactory {
public function createButton() {
Ligne 309 ⟶ 349 :
}
}
class OSXFactory extends GUIFactory {
public function createButton() {
Ligne 315 ⟶ 355 :
}
}
abstract class Button {
private $_caption;
Ligne 327 ⟶ 367 :
}
}
class WinButton extends Button {
public function render() {
Ligne 333 ⟶ 373 :
}
}
class OSXButton extends Button {
public function render() {
Ligne 339 ⟶ 379 :
}
}
$aFactory = GUIFactory::getFactory();
$aButton = $aFactory->createButton();
Ligne 345 ⟶ 385 :
echo $aButton->render();
//
// Je suis un WinButton: Démarrage
// ou :
// Je suis un OSXButton: Démarrage
</source>
Ligne 354 ⟶ 394 :
<source lang="eiffel">
get_factory: GUI_FACTORY is
once
inspect read_from_config_file("OS_TYPE")
when 0 then
create {WIN_FACTORY} Result
else
create {OSX_FACTORY} Result
end
end
create_button: BUTTON is deferred end
create_button: WIN_BUTTON is do create Result end
create_button: OSX_BUTTON is do create Result end
caption: STRING
set_caption(value: like caption) is do caption := value end
paint is deferred end
paint is do print("I'm a WIN_BUTTON: "+caption+"%N") end
paint is do print("I'm a OSX_BUTTON: "+caption+"%N") end
main is local button : BUTTON do
button := get_factory.create_button
button.set_caption("Play")
button.paint
end
</source>
[[Catégorie:Patrons de conception (livre)]]
|