Els patrons de disseny són solucions provades a problemes comuns en el desenvolupament de programari. Aquests patrons ajuden a crear codi més organitzat, reutilitzable i mantenible. En aquest tema, explorarem alguns dels patrons de disseny més comuns i com implementar-los en Delphi/Object Pascal.
Introducció als Patrons de Disseny
Què són els Patrons de Disseny?
- Definició: Un patró de disseny és una solució general reutilitzable per a un problema comú en un context de disseny de programari.
- Categories: Els patrons de disseny es classifiquen en tres categories principals:
- Patrons Creacionals: Tracten amb la creació d'objectes.
- Patrons Estructurals: Tracten amb la composició d'objectes.
- Patrons de Comportament: Tracten amb la interacció entre objectes.
Beneficis dels Patrons de Disseny
- Reutilització del Codi: Faciliten la reutilització de solucions provades.
- Mantenibilitat: Milloren la mantenibilitat del codi.
- Comunicació: Proporcionen un llenguatge comú per als desenvolupadors.
Patrons Creacionals
Patró Singleton
El patró Singleton assegura que una classe només tingui una instància i proporciona un punt d'accés global a aquesta instància.
Implementació en Delphi
type TSingleton = class private class var FInstance: TSingleton; constructor Create; reintroduce; public class function GetInstance: TSingleton; end; constructor TSingleton.Create; begin inherited Create; // Inicialització de l'objecte end; class function TSingleton.GetInstance: TSingleton; begin if not Assigned(FInstance) then FInstance := TSingleton.Create; Result := FInstance; end;
Explicació
- Constructor Privat: El constructor és privat per evitar la creació d'instàncies des de fora de la classe.
- Mètode Estàtic:
GetInstance
és un mètode estàtic que crea i retorna l'única instància de la classe.
Patró Factory
El patró Factory proporciona una interfície per crear objectes en una superclasse, però permet que les subclasses alterin el tipus d'objectes que es crearan.
Implementació en Delphi
type TProduct = class procedure Operation; virtual; abstract; end; TConcreteProductA = class(TProduct) procedure Operation; override; end; TConcreteProductB = class(TProduct) procedure Operation; override; end; TFactory = class function CreateProduct(AType: string): TProduct; end; procedure TConcreteProductA.Operation; begin // Implementació específica de ProductA end; procedure TConcreteProductB.Operation; begin // Implementació específica de ProductB end; function TFactory.CreateProduct(AType: string): TProduct; begin if AType = 'A' then Result := TConcreteProductA.Create else if AType = 'B' then Result := TConcreteProductB.Create else Result := nil; end;
Explicació
- Classe Producte:
TProduct
és una classe base amb un mètode abstracteOperation
. - Classes Concretes:
TConcreteProductA
iTConcreteProductB
són subclasses que implementenOperation
. - Classe Fàbrica:
TFactory
conté el mètodeCreateProduct
que crea instàncies deTProduct
basades en el tipus especificat.
Patrons Estructurals
Patró Adapter
El patró Adapter permet que classes amb interfícies incompatibles treballin juntes.
Implementació en Delphi
type TTarget = class procedure Request; virtual; end; TAdaptee = class procedure SpecificRequest; end; TAdapter = class(TTarget) private FAdaptee: TAdaptee; public constructor Create(AAdaptee: TAdaptee); procedure Request; override; end; procedure TTarget.Request; begin // Implementació per defecte end; procedure TAdaptee.SpecificRequest; begin // Implementació específica end; constructor TAdapter.Create(AAdaptee: TAdaptee); begin FAdaptee := AAdaptee; end; procedure TAdapter.Request; begin FAdaptee.SpecificRequest; end;
Explicació
- Classe Target:
TTarget
defineix l'interfície que el client espera. - Classe Adaptee:
TAdaptee
conté una interfície incompatible que necessita ser adaptada. - Classe Adapter:
TAdapter
adapta l'interfície deTAdaptee
a la interfície deTTarget
.
Patrons de Comportament
Patró Observer
El patró Observer defineix una dependència un-a-molts entre objectes de manera que quan un objecte canvia d'estat, tots els seus dependents són notificats i actualitzats automàticament.
Implementació en Delphi
type IObserver = interface procedure Update; end; TSubject = class private FObservers: TList<IObserver>; public constructor Create; destructor Destroy; override; procedure Attach(AObserver: IObserver); procedure Detach(AObserver: IObserver); procedure Notify; end; TConcreteObserver = class(TInterfacedObject, IObserver) public procedure Update; end; constructor TSubject.Create; begin FObservers := TList<IObserver>.Create; end; destructor TSubject.Destroy; begin FObservers.Free; inherited; end; procedure TSubject.Attach(AObserver: IObserver); begin FObservers.Add(AObserver); end; procedure TSubject.Detach(AObserver: IObserver); begin FObservers.Remove(AObserver); end; procedure TSubject.Notify; var Observer: IObserver; begin for Observer in FObservers do Observer.Update; end; procedure TConcreteObserver.Update; begin // Implementació de l'actualització end;
Explicació
- Interfície Observer:
IObserver
defineix el mètodeUpdate
que serà cridat perTSubject
. - Classe Subject:
TSubject
manté una llista d'observadors i els notifica quan hi ha un canvi d'estat. - Classe ConcreteObserver:
TConcreteObserver
implementa la interfícieIObserver
i defineix el comportament de l'actualització.
Exercicis Pràctics
Exercici 1: Implementar un Singleton
Implementa una classe Singleton que gestioni la configuració de l'aplicació.
Exercici 2: Crear una Fàbrica
Crea una fàbrica que generi diferents tipus de documents (per exemple, PDF, Word).
Exercici 3: Utilitzar un Adapter
Implementa un Adapter per adaptar una classe de registre de logs a una interfície de registre existent.
Exercici 4: Implementar un Observer
Crea un sistema de notificacions on diversos observadors reben actualitzacions d'un subjecte.
Solucions
Solució 1: Singleton
type TAppConfig = class private class var FInstance: TAppConfig; constructor Create; reintroduce; public class function GetInstance: TAppConfig; end; constructor TAppConfig.Create; begin inherited Create; // Inicialització de la configuració end; class function TAppConfig.GetInstance: TAppConfig; begin if not Assigned(FInstance) then FInstance := TAppConfig.Create; Result := FInstance; end;
Solució 2: Fàbrica
type TDocument = class procedure Open; virtual; abstract; end; TPDFDocument = class(TDocument) procedure Open; override; end; TWordDocument = class(TDocument) procedure Open; override; end; TDocumentFactory = class function CreateDocument(AType: string): TDocument; end; procedure TPDFDocument.Open; begin // Obrir document PDF end; procedure TWordDocument.Open; begin // Obrir document Word end; function TDocumentFactory.CreateDocument(AType: string): TDocument; begin if AType = 'PDF' then Result := TPDFDocument.Create else if AType = 'Word' then Result := TWordDocument.Create else Result := nil; end;
Solució 3: Adapter
type TLogTarget = class procedure LogMessage(AMessage: string); virtual; end; TLegacyLogger = class procedure WriteLog(AMessage: string); end; TLogAdapter = class(TLogTarget) private FLegacyLogger: TLegacyLogger; public constructor Create(ALegacyLogger: TLegacyLogger); procedure LogMessage(AMessage: string); override; end; procedure TLogTarget.LogMessage(AMessage: string); begin // Implementació per defecte end; procedure TLegacyLogger.WriteLog(AMessage: string); begin // Escriure log end; constructor TLogAdapter.Create(ALegacyLogger: TLegacyLogger); begin FLegacyLogger := ALegacyLogger; end; procedure TLogAdapter.LogMessage(AMessage: string); begin FLegacyLogger.WriteLog(AMessage); end;
Solució 4: Observer
type IObserver = interface procedure Update; end; TSubject = class private FObservers: TList<IObserver>; public constructor Create; destructor Destroy; override; procedure Attach(AObserver: IObserver); procedure Detach(AObserver: IObserver); procedure Notify; end; TConcreteObserver = class(TInterfacedObject, IObserver) public procedure Update; end; constructor TSubject.Create; begin FObservers := TList<IObserver>.Create; end; destructor TSubject.Destroy; begin FObservers.Free; inherited; end; procedure TSubject.Attach(AObserver: IObserver); begin FObservers.Add(AObserver); end; procedure TSubject.Detach(AObserver: IObserver); begin FObservers.Remove(AObserver); end; procedure TSubject.Notify; var Observer: IObserver; begin for Observer in FObservers do Observer.Update; end; procedure TConcreteObserver.Update; begin // Implementació de l'actualització end;
Conclusió
En aquest tema, hem explorat diversos patrons de disseny i com implementar-los en Delphi/Object Pascal. Els patrons de disseny són eines poderoses que poden millorar significativament la qualitat del teu codi. Practica aquests patrons amb els exercicis proporcionats per consolidar el teu coneixement i prepara't per aplicar-los en projectes reals.
Curs de Programació Delphi/Object Pascal
Mòdul 1: Introducció a Delphi/Object Pascal
- Introducció a Delphi i Object Pascal
- Configuració de l'Entorn de Desenvolupament
- Primera Aplicació Delphi
- Sintaxi i Estructura Bàsiques
- Variables i Tipus de Dades
Mòdul 2: Estructures de Control i Procediments
- Declaracions Condicionals
- Bucles i Iteració
- Procediments i Funcions
- Abast i Durada de les Variables
- Gestió d'Errors i Depuració
Mòdul 3: Treballant amb Dades
- Arrays i Cadenes
- Registres i Conjunts
- Tipus Enumerats i Subrang
- Gestió d'Arxius
- Accés a Bases de Dades
Mòdul 4: Programació Orientada a Objectes
- Introducció a la POO
- Classes i Objectes
- Herència i Polimorfisme
- Interfícies i Classes Abstractes
- Gestió d'Excepcions en POO
Mòdul 5: Funcions Avançades de Delphi
- Generics i Col·leccions
- Multifil i Programació Paral·lela
- Desenvolupament Basat en Components
- Biblioteca d'Execució de Delphi (RTL)
- Tècniques Avançades de Depuració
Mòdul 6: Desenvolupament d'Interfícies Gràfiques amb VCL i FMX
- Introducció a VCL
- Creació de Formularis i Controls
- Programació Basada en Esdeveniments
- Introducció a FireMonkey (FMX)
- Desenvolupament Multiplataforma amb FMX
Mòdul 7: Desenvolupament Web i Mòbil
- Desenvolupament Web amb Delphi
- Serveis RESTful
- Desenvolupament Mòbil amb Delphi
- Desplegament d'Aplicacions Mòbils
- Integració amb Serveis Web
Mòdul 8: Millors Pràctiques i Patrons de Disseny
- Organització del Codi i Documentació
- Patrons de Disseny en Delphi
- Tècniques de Refactorització
- Proves Unitàries i Desenvolupament Basat en Proves
- Optimització del Rendiment