mercredi 15 septembre 2010

Creational Patterns

1) Abstract factory :

Utilisé pour gérer de multiples look & feel ou source de données, on évite de créer des instances d’une classe particulière directement dans l’application. On passe par une classe intermédiaire qui se charge de créer les objets pour nous.

Nous allons appliquer ce pattern à TrialXS. Supposons que nous voulions rendre l’application indépendante du type de server de base de données (ce qui complique la tâche). Nous allons considérer deux server de base de données SQL Server et Oracle.

Exemple :
// Abstract Factory
TDBObjectFactory=class
function CreateProject :TProject;virtual;
function CreatePatient;TPatient;virtual;

End;
// Abstract Product
TDBObject=class
Procedure get;virtual;
Procedure Save;virtual;
Function createsql:string;virtual;
End;
TProject=class(TDBObject)
property BaseLine : integer read fBaseLine;
end;
TPatient=class(TDBObject)
end;
// Concrete Product
TSqlProject=class(TProject)
Function createsql:string;override //Contient le sql de creation de l’objet pour Sql server
Function Save ;override ;
Function get ; override ;
End ;
// Concrete product
TOraProject=class(TProject)
Function createsql:string;override //Contient le sql de creation de l’objet pour Oracle
Function Save ;override ;
Function get ; override ;
End ;
// Concrete Factory
TSqlObjectFactory =class(TDBObjectFactory)
Function CreateProject ;override; // Retourne un objet TSqlProject
function CreatePatient;override;
End;
// Concrete Factory
TOraObjectFactory=class(TDBObjectFactory)
function CreateProject ;override; // retourne un objet TOraProject
function CreatePatient;override;
End;

Dans l’initialisation de l’application

Var
ObjectFactory:TDBObjectFactory;
begin
If db_type=sql then
ObjectFactory:=TSqlObjectFactory.Create;
Else
ObjectFactory:=TOraObjectFactory.Create;
End;

Chaque fois que je crée un objet db dans l’application, je passerai par l’objet ObjectFactory. En faisant soit

Var
Project :TProject ;
begin
Project :=ObjectBuilder.CreateProject ;
Project.get;
end;

Ceci Va me donner un objet de type SqlProject ou OraProject suivant le type de serveur sql utilisé. Partout dans l’application j’utiliserai l’interface de TProject en me moquant de savoir si j’ai un OraProject ou un SqlProject puisqu’ils réalisent tous deux la même interface. Ce système, certe plus lourd à le mérite d’éviter les castings.

Cela signifie que le type de server sql est défini une fois, partout ailleurs dans l’application je me ficherais de savoir si j’utilise Oracle ou SQL Server puisque c’est l’instance de la classe TDBObjectFactory (ObjectFactory) qui appellera les bon constructeur de classe.
Mon application sera donc indépendante du server de base de donnée pour récupérer ses objets.
TDBObjectFactory ou TDBObject sont généralement considérées comme des classes abstraites ou des interfaces, elles ne peuvent pas être instanciée directement.

Avantage: permet de changer toute une famille de produit en une fois.
Inconvénient:Il n'est pas facile d'ajouter un nouveau produit, car il faut updater et créer plusieurs classes. (pas très flexible)

On utilise souvent l'abstract Factory avec le pattern Singleton, car on ne doit avoir qu'une instance de la Concrete Factory.

On appelle également ce pattern :Kit ou Usine (terme français pour Factory)

2 commentaires:

  1. Très intéressant.
    Dans la classe TDBObjectFactory, le type de retour pour CreateProject ne devrait-il pas être TDBObject?
    Et pareil pour CreatePatient?

    RépondreSupprimer
  2. Merci Dominique pour les commentaires, il y a avait en effet des erreurs énormes.

    Je dirai pour ta question oui et non. D'une part on pourrait utiliser un TDBObject mais idéalement il faudrait que l'utilisateur le caste, ce qui est un peu ennuyeux.

    Ici j'utilise un TProject qui dérive de TDBObject, ce qui signifie qu'il bénéficie des méthodes d'accès à la DB (get en particulier) mais qu'il peut disposer de ses propres méthodes ou propriétés (ex: GetBaseline).

    L'avantage de faire dériver SQLProject ou OraProject de TProject signifie que quelque soit le type de DB le factory me renverra un TProject (on renvoit un casting sur la classe parent, car c'est elle que je vais utiliser dans mon appli).

    Cette méthode est sans doute lourde mais elle a l'avantage d'éviter de caster les objets.

    Voilà, merci pour ton com, j'espère que ça répond à ta question.

    Je te recontacte bientôt par mail !
    A+,

    jyce.

    RépondreSupprimer