unit uclasses;

interface

uses uIntfs, classes, Sysutils;

type
  TAuthor = class;
  TCategory = class;
  TBook = class;

  TPortfolio = class(TInterfacedObject, IPortfolio)
  private
    aSL : TStringList;
    FAuthor : TAuthor;
  public
    Constructor Create;
    Destructor Destroy; override;
    function GetAuthors : TStringList; stdcall;
    function GetBooks(const sName : String) : TStringList; stdcall;
  end;

  TAuthor = class(TInterfacedObject, IAuthor)
  private
    FName : String;
    FCategory : TCategory;
    aSL : TStringList;
  public
    Constructor Create(const sName : String);
    Destructor Destroy; override;
    function GetName : String;
    function GetCategories : TStringList; stdcall;
  end;

  TCategory = class(TInterfacedObject, ICategory)
  private
    FName : String;
    aSL : TStringList;
    FBook : TBook;
  public
    Constructor Create(const sName : String);
    Destructor Destroy; override;
    function GetName : String;
    function GetBooks : TStringList; stdcall;
    procedure CreateBook(const sName : String; const iPrice : Integer);
  end;

  TBook = class(TObject)
  private
    FName : String;
    FPrice : Integer;
  public
    Constructor Create(const sName : String; const iPrice : Integer);
    function GetName : String;
    function GetPrice : Integer;
  end;

implementation

{ TPortfolio }

constructor TPortfolio.Create;
begin
  aSL := TStringList.Create;
  FAuthor := TAuthor.Create('李维');
  aSL.AddObject(FAuthor.GetName, FAuthor);
end;

destructor TPortfolio.Destroy;
begin
  FreeAndNil(FAuthor);
  FreeAndNil(aSL);
  inherited;
end;

function TPortfolio.GetAuthors: TStringList;
begin
  Result := aSL;
end;

function TPortfolio.GetBooks(const sName: String): TStringList;
var
  idx : Integer;
  rSL : TStringList;
  iCount : Integer;
  iCount1 : Integer;
  FCategory : TCategory;
begin
  rSL := nil;
  //根据sName找到TAuthor
  if (aSL.Find(sName, idx)) then
  begin
    FAuthor := TAuthor(aSL.Objects[idx]);
    rSL := TStringList.Create;

    for iCount := 0 to FAuthor.aSL.Count - 1 do
    begin
      FCategory := TCategory(FAuthor.aSL.Objects[iCount]);
      for iCount1 := 0 to FCategory.aSL.Count - 1 do
      begin
        rSL.AddObject(FCategory.aSL.Strings[iCount1], FCategory.aSL.Objects[iCount1])
      end;
    end
  end;
  Result := rSL;
end;

{ TAuthor }

constructor TAuthor.Create(const sName: String);
begin
  aSL := TStringList.Create;
  FName := sName;
  FCategory := TCategory.Create('Delphi');
  FCategory.CreateBook('Delphi 5 系统篇', 680);
  FCategory.CreateBook('Delphi 6 Web Service', 600);
  FCategory.CreateBook('Delphi 7 dbExpress', 600);
  aSL.AddObject(FCategory.GetName, FCategory);


  FCategory := TCategory.Create('C++Builder');
  FCategory.CreateBook('C++Builder 6 SOAP/Web Service', 600);
  aSL.AddObject(FCategory.GetName, FCategory);

  FCategory := TCategory.Create('.NET');
  FCategory.CreateBook('Delphi.NET Developer Guide', 680);
  aSL.AddObject(FCategory.GetName, FCategory);
end;

destructor TAuthor.Destroy;
var
  iCount : Integer;
begin
  for iCount := aSL.Count - 1 downto 0 do
  begin
    FCategory := TCategory(aSL.Objects[iCount]);
    FreeAndNil(FCategory);
  end;
  aSL.Clear;
  FreeAndNil(aSL);
  inherited;
end;

function TAuthor.GetCategories: TStringList;
begin
  Result := aSL;
end;

function TAuthor.GetName: String;
begin
  Result := FName;
end;

{ TCategory }

constructor TCategory.Create(const sName: String);
begin
  aSL := TStringList.Create;
  FName := sName;
end;

procedure TCategory.CreateBook(const sName: String; const iPrice: Integer);
begin
  FBook := TBook.Create(sName, iPrice);
  aSL.AddObject(FBook.GetName, FBook);
end;

destructor TCategory.Destroy;
var
  iCount : Integer;
begin
  for iCount := aSL.Count - 1 downto 0 do
  begin
    FBook := TBook(aSL.Objects[iCount]);
    FreeAndNil(FBook);
  end;
  aSL.Clear;
  FreeAndNil(aSL);
  inherited;
end;

function TCategory.GetBooks: TStringList;
begin
  Result := aSL;
end;

function TCategory.GetName: String;
begin
  Result := FName;
end;

{ TBooks }

constructor TBook.Create(const sName: String; const iPrice: Integer);
begin
  FName := sName;
  FPrice := iPrice;
end;

function TBook.GetName: String;
begin
  Result := FName;
end;

function TBook.GetPrice: Integer;
begin
  Result := FPrice;
end;

end.
