« 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}}
La '''fabrique abstraite''' est un [[patron de conception]] ''(design pattern)'' [[Patron de conception#Création|créationnel]] utilisé en [[génie logiciel]].
 
Une fabrique abstraite encapsule un groupe de [[../Fabrique (patron de conception)|fabriques]] ayant une thématique commune.
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'[[objet (informatique)|objet]] ''concret'' qu'il faut créer, et c'est ici que l'objet est effectivement créé (dans le cas dude C++, Java et C#, c'est l'[[instruction]] '''new'''). Cependant, la fabrique retourne un [[pointeur (programmation)|pointeur]] ''abstrait'' ou une référence ''abstraite'' sur l'objet concret créé.
 
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 headerd'en-tête ou déclaration de classe requis par le type concret. Le code client n'interagit qu'avec la classe abstraite. Les objets concrets sont en effet créés par la fabrique, et le code client ne les manipule qu'avec leur interface abstraite.
* 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 ==
== Structure ==
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.svg de classes du patron de conception Fabrique Abstraite]]
 
== Exemples ==
Ligne 27 ⟶ 30 :
 
<source lang="cpp">
/* exemple d'une fabrique abstraite d'eléments d'IHM en C++ */
 
struct Button
{
virtual void paint() = 0;
};
 
struct WinButton : public Button
{
void paint (){
{
std::cout << " I'm a window button \n";
std::cout << " I'm a window button \n";
}
}
};
 
struct OSXButton : public Button
{
void paint (){
{
std::cout << " I'm a OSX button \n";
std::cout << " I'm a OSX button \n";
}
}
};
 
struct GUIFactory
{
virtual Button* createButton () = 0;
};
 
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* 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
* GUIFactory example
*/
abstract class GUIFactory
{
abstract class GUIFactory {
public static GUIFactory getFactory() {
{
int sys = readFromConfigFile("OS_TYPE");
int ifsys = readFromConfigFile(sys==0"OS_TYPE") {;
if (sys==0)
return(new WinFactory());
} else {
return(new OSXFactory());
}
}
 
public abstract Button createButton();
}
 
class WinFactory:GUIFactory
{
public override Button createButton() {
{
return(new WinButton());
}
}
 
class OSXFactory:GUIFactory
{
public override Button createButton() {
{
return(new OSXButton());
}
}
 
abstract class Button
{
public string caption;
public abstract void paint();
}
 
class WinButton:Button
{
public override void paint() {
{
Console.WriteLine("I'm a WinButton: "+caption);
}
}
 
class OSXButton:Button
{
public override void paint() {
{
Console.WriteLine("I'm a OSXButton: "+caption);
}
}
 
class Application
{
static void Main(string[] args) {
{
GUIFactory aFactory = GUIFactory.getFactory();
GUIFactory Button aButtonaFactory = aFactoryGUIFactory.createButtongetFactory();
Button aButton.caption = "Play"aFactory.createButton();
aButton.paint()caption = "Play";
} aButton.paint();
//output is}
//I'm aaffiche WinButton: Play
// I'm a WinButton: Play
//or
// ou :
// I'm a OSXButton: Play
}
</source>
 
Ligne 149 ⟶ 175 :
 
<source lang="java">
/*
* GUIFactory example
*/
public abstract class GUIFactory
{
public abstract class GUIFactory {
public static GUIFactory getFactory() {
{
int sys = readFromConfigFile("OS_TYPE");
int if (sys == 0readFromConfigFile("OS_TYPE") {;
if (sys == 0)
return(new WinFactory());
} else {
return(new OSXFactory());
}
}
public abstract Button createButton();
}
 
class WinFactory extends GUIFactory
{
public Button createButton() {
{
return(new WinButton());
}
}
 
class OSXFactory extends GUIFactory
{
public Button createButton() {
{
return(new OSXButton());
}
}
 
public abstract class Button
{
private String caption;
public abstract void paint();
public String getCaption(){
{
return caption;
}
 
public void setCaption(String caption){
public void this.caption =setCaption(String caption;)
}{
this.caption = caption;
}
}
}
class WinButton extends Button
{
public void paint() {
{
System.out.println("I'm a WinButton: "+ getCaption());
}
}
 
class OSXButton extends Button
{
public void paint() {
{
System.out.println("I'm a OSXButton: "+ getCaption());
}
}
 
public class Application
{
public static void main(String[] args) {
{
GUIFactory aFactory = GUIFactory.getFactory();
GUIFactory Button aButtonaFactory = aFactoryGUIFactory.createButtongetFactory();
Button aButton = aFactory.setCaptioncreateButton("Play");
aButton.paintsetCaption("Play");
} aButton.paint();
//output is}
//I'm aaffiche WinButton: Play
// I'm a WinButton: Play
//or
// ou :
// I'm a OSXButton: Play
}
</source>
 
Ligne 218 ⟶ 258 :
 
<source lang="perl">
# GUIFactory example on Perl
 
package GUIFactory;
 
sub getFactory($$) {
shift; # skip class
my $toolkit = shift;
if ($toolkit eq 'GTK') {
return(GtkFactory->new);
} else {
return(TkFactory->new);
}
}
 
package GtkFactory;
use base 'GUIFactory';
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";
}
sub new {
package main;
bless({}, shift);
}
my $aFactory = GUIFactory->getFactory;
 
my $aButton = $aFactory->createButton;
sub createButton {
$aButton->{caption} = "Play";
return(GtkButton->new);
$aButton->paint();
}
 
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();
 
//Le renduaffiche est:
// Je suis un WinButton: Démarrage
// ou :
// Je suis un OSXButton: Démarrage
</source>
 
Ligne 354 ⟶ 394 :
 
<source lang="eiffel">
--
-- GUI Factory example
--
class GUI_FACTORY_FOR_CONFIG feature
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
end
 
deferred class GUI_FACTORY feature
create_button: BUTTON is deferred end
end
 
class WIN_FACTORY inherit GUI_FACTORY feature
create_button: WIN_BUTTON is do create Result end
end
 
class OSX_FACTORY inherit GUI_FACTORY feature
create_button: OSX_BUTTON is do create Result end
end
 
deferred class BUTTON feature
caption: STRING
set_caption(value: like caption) is do caption := value end
paint is deferred end
end
 
class WIN_BUTTON inherit BUTTON feature
paint is do print("I'm a WIN_BUTTON: "+caption+"%N") end
end
 
class OSX_BUTTON inherit BUTTON feature
paint is do print("I'm a OSX_BUTTON: "+caption+"%N") end
end
 
class APPLICATION inherit GUI_FACTORY_FOR_CONFIG creation main feature
main is local button : BUTTON do
button := get_factory.create_button
button.set_caption("Play")
button.paint
end
end
</source>
 
[[Catégorie:Patrons de conception (livre)]]
{{Portail informatique}}
 
[[Catégorie:Patron de conception]]
[[Catégorie:Architecture logicielle]]
[[bg:Абстрактна Фабрика (шаблон)]]
[[ca:Abstract factory]]
[[de:Abstrakte Fabrik]]
[[en:Abstract factory pattern]]
[[es:Abstract Factory (patrón de diseño)]]
[[it:Abstract factory]]
[[ja:Abstract Factory パターン]]
[[ko:Abstract factory 패턴]]
[[pl:Fabryka abstrakcyjna (wzorzec projektowy)]]
[[pt:Abstract Factory]]
[[ru:Абстрактная фабрика (шаблон проектирования)]]
[[th:Abstract factory pattern]]
[[uk:Абстрактна фабрика (шаблон проектування)]]
[[vi:Abstract factory pattern]]
[[zh:抽象工厂]]