Mi viene in mente la combinazione di fabbrica con Strategia . Ogni animale può supportare la nozione di un insieme di comportamenti che possono essere aggiunti / passati come una matrice di riferimenti all'interfaccia comportamentale o array di istanze di discendenti di una classe di comportamento astratta.
Non pensate che questa sia la strada da percorrere, poiché significa che decidete quali comportamenti devono passare al di fuori della fabbrica e ciò sembra vanificare lo scopo di avere una fabbrica in primo luogo.
Builder sembra specificamente adatto al tuo problema. Ho sempre considerato Builder come un'estensione (non nell'eredità ma nel senso di "prendere un ulteriore passo avanti"). Invece di concentrarsi sull'istanza, si rivolge in particolare alla costruzione di istanze di classi che richiedono più di una semplice chiamata a un costruttore.
Aggiornamento:
Di seguito è riportato un esempio del pattern Builder. Utilizza la sintassi Delphi in quanto è la lingua con cui ho più familiarità, ma mi sono astenuto dall'usare costrutti specifici di Delphi (meta-classi per esempio). Anche il controllo degli errori e la liberazione delle istanze sono stati esclusi dall'esempio.
Si noti che invece di passare al director un'istanza di un builder, è anche possibile passare una stringa e consentire al director di stabilire quale builder istanziare e utilizzare. In tal caso, opterei per un registro di builder nel director e un metodo di registrazione per il director in modo da poter dichiarare e creare builder senza modificare il director.
type
TBehaviour = class(TObject)
end;
TSpeakBehaviour = class(TBehaviour);
TJumpBehaviour = class(TBehaviour);
TAnimal = class(TObject)
public
procedure AddBehaviour(const aBehaviour: TBehaviour);
end;
TCat = class(TAnimal);
TDog = class(TAnimal);
TAnimalBuilder = class(TObject)
public
procedure BuildBody; virtual; abstract;
procedure AddBehaviours; virtual; abstract;
function GetAnimal: TAnimal; virtual; abstract;
end;
TCatBuilder = class(TBuilder)
private
FCat: TCat;
public
procedure BuildBody; override;
procedure AddBehaviours; override;
function GetAnimal: TAnimal; override;
end;
TDogBuilder = class(TBuilder)
private
FDog: TDog;
public
procedure BuildBody; override;
procedure AddBehaviours; override;
function GetAnimal: TAnimal; override;
end;
TAnimalDirector = class(TObject)
private
FBuilder: TAnimalBuilder;
public
constructor Create(const aBuilder: TAnimalBuilder);
function BuildAnimal: TAnimal;
end;
procedure BuildMeAnAnimal;
var
Builder: TAnimalBuilder;
Director: TAnimalDirector;
Animal: TAnimal;
begin
Builder := TCatBuilder.Create;
Director := TAnimalDirector.Create(Builder);
Animal := Director.BuildAndimal;
end;
//--- Animal Director --------------
constructor TAnimalDirector.Create(const aBuilder: TAnimalBuilder);
begin
FBuilder := aBuilder;
end;
function TAnimalDirector.BuildAnimal: TAnimal;
begin
FBuilder.BuildBody;
FBuilder.AddBehaviours;
Result := FBuilder.GetAnimal;
end;
//--- Cat Builder --------------
procedure TCatBuilder.BuildBody;
begin
FCat := TCat.Create;
end;
procedure TCatBuilder.AddBehaviours;
begin
FCat.AddBehaviour(TSpeakBehaviour.Create('miauw'));
FCat.AddBehaviour(TJumpBehaviour.Create(jaHigh));
end;
function TCatBuilder.GetAnimal: TAnimal;
begin
Result := FCat;
end;
//--- Dog Builder --------------
procedure TDogBuilder.BuildBody;
begin
FDog := TDog.Create;
end;
procedure TDogBuilder.AddBehaviours;
begin
FDog.AddBehaviour(TSpeakBehaviour.Create('woof'));
FDog.AddBehaviour(TJumpBehaviour.Create(jaMediumHigh));
end;
function TDogBuilder.GetAnimal: TAnimal;
begin
Result := FDog;
end;