Design Pattern----01.Creational.AbstractFactory.Pattern (Delphi Sample)

Intent

  • Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
  • A hierarchy that encapsulates: many possible “platforms”, and the construction of a suite of “products”.
  • The new operator considered harmful.

Problem

  • If an application is to be portable, it needs to encapsulate platform dependencies. These “platforms” might include: windowing system, operating system, database, etc. Too often, this encapsulatation is not engineered in advance, and lots of #ifdef case statements with options for all currently supported platforms begin to procreate like rabbits throughout the code.

Discussion

  • Provide a level of indirection that abstracts the creation of families of related or dependent objects without directly specifying their concrete classes. The “factory” object has the responsibility for providing creation services for the entire platform family. Clients never create platform objects directly, they ask the factory to do that for them.
  • This mechanism makes exchanging product families easy because the specific class of the factory object appears only once in the application - where it is instantiated. The application can wholesale replace the entire family of products simply by instantiating a different concrete instance of the abstract factory.
  • Because the service provided by the factory object is so pervasive, it is routinely implemented as a Singleton.

Structure

  • The Abstract Factory defines a Factory Method per product. Each Factory Method encapsulates the new operator and the concrete, platform-specific, product classes. Each “platform” is then modeled with a Factory derived class.

Scheme of Abstract Factory

Example

  • The purpose of the Abstract Factory is to provide an interface for creating families of related objects, without specifying concrete classes. This pattern is found in the sheet metal stamping equipment used in the manufacture of Japanese automobiles. The stamping equipment is an Abstract Factory which creates auto body parts. The same machinery is used to stamp right hand doors, left hand doors, right front fenders, left front fenders, hoods, etc. for different models of cars. Through the use of rollers to change the stamping dies, the concrete classes produced by the machinery can be changed within three minutes.

Example of Abstract Factory

Check list

  1. Decide if “platform independence” and creation services are the current source of pain.
  2. Map out a matrix of “platforms” versus “products”.
  3. Define a factory interface that consists of a factory method per product.
  4. Define a factory derived class for each platform that encapsulates all references to the new operator.
  5. The client should retire all references to new, and use the factory methods to create the product objects.

Rules of thumb

  • Sometimes creational patterns are competitors: there are cases when either Prototype or Abstract Factory could be used profitably. At other times they are complementary: Abstract Factory might store a set of Prototypes from which to clone and return product objects, Builder can use one of the other patterns to implement which components get built. Abstract Factory, Builder, and Prototype can use Singleton in their implementation.
  • Abstract Factory, Builder, and Prototype define a factory object that’s responsible for knowing and creating the class of product objects, and make it a parameter of the system. Abstract Factory has the factory object producing objects of several classes. Builder has the factory object building a complex product incrementally using a correspondingly complex protocol. Prototype has the factory object (aka prototype) building a product by copying a prototype object.
  • Abstract Factory classes are often implemented with Factory Methods, but they can also be implemented using Prototype.
  • Abstract Factory can be used as an alternative to Facade to hide platform-specific classes.
  • Builder focuses on constructing a complex object step by step. Abstract Factory emphasizes a family of product objects (either simple or complex). Builder returns the product as a final step, but as far as the Abstract Factory is concerned, the product gets returned immediately.
  • Often, designs start out using Factory Method (less complicated, more customizable, subclasses proliferate) and evolve toward Abstract Factory, Prototype, or Builder (more flexible, more complex) as the designer discovers where more flexibility is needed.

Abstract Factory in Delphi

source url:http://delphipatterns.blog.com/

UML

image

source:

unit AbstractFactory;

interface

type
  // the brands definition
  IBrand = interface
  ['{3D8E5363-08E7-4B8F-ABF1-8953E13C7A9A}']
    function Price: integer;
    function Material: string;
  end;

  TGucci = class(TInterfacedObject, IBrand)
  public
    function Price: integer;
    function Material: string;
  end;

  TPoochy = class(TInterfacedObject, IBrand)
  public
    function Price: integer;
    function Material: string;
  end;
  // the products definition
  IBag = interface
  ['{7EACC8B1-7963-4677-A8D7-9FA62065B880}']
    function Material: string;
  end;

  IShoes = interface
  ['{1560A332-D2D1-43E1-99BB-3D2882C1501A}']
    function Price: integer;
  end;

  TBag = class(TInterfacedObject, IBag)
  private
    FMyBrand: IBrand;
  public
    constructor Create(brand: IBrand);
    function Material: string;
  end;

  TShoes = class(TInterfacedObject, IShoes)
  private
    FMyBrand: IBrand;
  public
    constructor Create(brand: IBrand);
    function Price: integer;
  end;
  // factories definition
  IFactory = interface
  ['{A9948727-DA7C-4843-83CF-92B81DD158F9}']
    function CreateBag: IBag;
    function CreateShoes: IShoes;
  end;

  TGucciFactory = class(TInterfacedObject, IFactory)
  public
    function CreateBag: IBag;
    function CreateShoes: IShoes;
  end;

  TPoochyFactory = class(TInterfacedObject, IFactory)
  public
    function CreateBag: IBag;
    function CreateShoes: IShoes;
  end;

implementation

{ TGucci }

function TGucci.Material: string;
begin
  Result := 'Crocodile skin';
end;

function TGucci.Price: integer;
begin
  Result := 1000;
end;

{ TPoochi }

function TPoochy.Material: string;
begin
  Result := 'Plastic';
end;

function TPoochy.Price: integer;
var
  gucci: TGucci;
begin
  gucci := TGucci.Create;
  try
    Result := Round(gucci.Price / 3);
  finally
    gucci.Free;
  end;
end;

{ TBag }

constructor TBag.Create(brand: IBrand);
begin
  inherited Create;
  FMyBrand := brand;
end;

function TBag.Material: string;
begin
  Result := FMyBrand.Material;
end;

{ TShoes }

constructor TShoes.Create(brand: IBrand);
begin
  inherited Create;
  FMyBrand := brand;
end;

function TShoes.Price: integer;
begin
  Result := FMyBrand.Price;
end;

{ TGucciFactory }

function TGucciFactory.CreateBag: IBag;
begin
  Result := IBag(TBag.Create(TGucci.Create));
end;

function TGucciFactory.CreateShoes: IShoes;
begin
  Result := IShoes(TShoes.Create(TGucci.Create));
end;

{ TPoochyFactory }

function TPoochyFactory.CreateBag: IBag;
begin
  Result := IBag(TBag.Create(TPoochy.Create));
end;

function TPoochyFactory.CreateShoes: IShoes;
begin
  Result := IShoes(TShoes.Create(TPoochy.Create));
end;

end.

-------------------------------------------------------------------------------------------------------------------------

program AbstractFactory.Pattern;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  AbstractFactory in 'AbstractFactory.pas';

var
  bag: IBag;
  shoes: IShoes;
  factory: IFactory;

begin
//  ReportMemoryLeaksOnShutDown := DebugHook  0;
  try
    factory := TGucciFactory.Create;
    bag := factory.CreateBag;
    shoes := factory.CreateShoes;

    WriteLn('I bought a Bag which is made from ' + bag.Material);
    WriteLn('I bought some shoes which cost ' + IntToStr(shoes.Price));

    factory := TPoochyFactory.Create;
    bag := factory.CreateBag;
    shoes := factory.CreateShoes;

    WriteLn('I bought a Bag which is made from ' + bag.Material);
    WriteLn('I bought some shoes which cost ' + IntToStr(shoes.Price));

    ReadLn;
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
end.
 
----------------------------------
Result:
7__320x240_abstractfactory-result 

spaghetti [spə'ɡeti]

  • · n. 意大利式细面条

concrete [kən'kri:t, 'kɔnkri:t]

  • · adj. 混凝土的;实在的,具体的;有形的
  • · vi. 凝结
  • · vt. 使凝固;用混凝土修筑
  • · n. 具体物;凝结物

suite [swi:t]

  • · n. 组曲;套房;(一批)随员,随从;(一套)家具

portable ['pɔ:təbl, 'pəu-]

  • · adj. 手提的,便携式的;轻便的
  • · n. 手提式打字机

engineer [,endʒi'niə]

  • · n. 工程师;工兵;火车司机
  • · vt. 策划;设计;精明地处理
  • · vi. 设计;建造

platform ['plætfɔ:m]

  • · n. 平台;月台,站台;坛;讲台

procreate ['prəukrieit]

  • · vi. 生育(子女);产生
  • · vt. 生殖

throughout [θru:'aut]

  • · adv. 自始至终,到处;全部
  • · prep. 贯穿,遍及

indirection [,indi'rekʃən, -dai-]

  • · n. 间接;迂回;不坦率

brand [brænd]

  • vt. 铭刻于,铭记;打烙印于;印…商标于
  • n. 商标,牌子;烙印

pervasive [pə:'veisiv, pə-]

  • adj. 普遍的;到处渗透的

    wholesale ['həulseil]

    • adj. 批发的;大规模的
    • n. 批发
    • adv. 大规模地;以批发方式
    • vt. 批发
    • vi. 批发;经营批发业

    routinely [ru:'ti:nli]

  • adv. 例行公事地;老一套地

  • posted on 2011-06-16 17:33  Tony Liu  阅读(712)  评论(0编辑  收藏  举报

    导航