AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Aufbau logisch und korrekt?

Ein Thema von ChEeTaH · begonnen am 15. Jan 2010 · letzter Beitrag vom 15. Jan 2010
Antwort Antwort
ChEeTaH

Registriert seit: 12. Jan 2009
49 Beiträge
 
Delphi XE2 Architect
 
#1

Aufbau logisch und korrekt?

  Alt 15. Jan 2010, 21:31
Hallo
Ich habe vor eine Parser-Klasse zu schreiben, die verschiedene Dienste im Internet Parst und formatiert ausgibt. Meine Klasse soll vorerst Google, Milw0rm, Heise, Gulli, Tecchannel und Wikipedia unterstützen. Ich lese dabei den Titel und wenn verfügbar den Link der jeweiligen Seite aus.

Bsp. Google:
Benutzer gibt Query 'delphi forum' ein.
Klasse gibt als Titel (in dem Fall der erste Googleeintrag) 'Delphi-PRAXIS - Hier werden sie geholfen' aus und als Link 'http://delphipraxis.net'.

Die Klasse soll später in einen IRC Bot Integriert werden, also arbeitet sie Zeilenbasiert.
(Das nur nebenbei, ist eher unwichtig. Mein Ziel ist es erstmal die Klasse zu schreiben).

Nun möchte ich von euch Wissen, ob mein Aufbau logisch und strukturiert erscheint oder ob ich etwas verbessern kann. Das Programm ist noch nicht fertig, es ist lediglich der Ansatz da und möchte Wissen ob der Ansatz korrekt ist.

Allgemeiner Aufbau:
Rahmen-Klasse: TParseServices (wird aufgerufen)
Delphi-Quellcode:
...
PS.Service := svGoogle;
PS.Query := 'delphi forum';
PS.Submit; {Submit liest den Service aus und übergibt dann den Query an die jeweilige UnterKlasse}

Titel := PS.GetResult.Title.Strings[0]; // Gibt 'Delphi-PRAXIS - Hier werden sie geholfen'
Link := PS.GetResult.Link.Strings[0]; // Gibt 'http://delphipraxis.net'

uParseServices:
Delphi-Quellcode:
unit uParseServices;

interface
uses IdBaseComponent, IdComponent, IdTCPConnection,
  IdTCPClient, IdHTTP, StrUtils, Classes;

type
  TServices = (svGoogle, svMilw0rm, svHeise, svGulli, svTecchannel,
    svWikipedia);

type
  TResult = record
    Title: TStrings;
    Link: TStrings;
  end;

type
  TPattern = record
    FBegin: string;
    FEnd: string;
  end;

type
  TGoogle = class
  private
    FPatternTitle: TPattern;
    FPatternLink: TPattern;
    FQueryURL: string;
    function Parse: TResult;
  end;

type
  TMilw0rm = class
  private
    FPatternTitle: TPattern;
    FQueryURL: string;
    function Parse: TResult;
  end;

type
  THeise = class
  private
    FQueryURL: string;
    function Parse: TResult;
  end;

type
  TGulli = class
  private
    FQueryURL: string;
    function Parse: TResult;
  end;

type
  TTecChannel = class
  private
    FQueryURL: string;
    function Parse: TResult;
  end;

type
  TWikipedia = class
  private
    FPatternTitle: TPattern;
    FPatternArticle: TPattern;
    FQueryURL: string;
    function Parse: string; // Erster Artikel
  end;

{(*}const
      GoogleURL = 'http://google.de/?q=[<QUERY>]';
      Milw0rmURL = 'http://milw0rm.com/?q=[<QUERY>]';
      HeiseURL = 'http://heise.de/?q=[<QUERY>]';
      GulliURL = 'http://gulli.com/?q=[<QUERY>]';
      TecChannelURL = '...[<QUERY>]';
      WikipediaURL = 'http://wikipedia.de/go?q=[<QUERY>]&l=de&e=wikipedia&s=suchen&b=suchen'; {*)}

type
  TParseServices = class

  private
    FResponse: string;
    FQuery: string;
    FService: TServices;
    FFilterdLinks: TStrings;
    FFilterdTitles: TStrings;

    Google: TGoogle;
    Milw0rm: TMilw0rm;
    Heise: THeise;
    Gulli: TGulli;
    TecChannel: TTecChannel;
    Wikipedia: TWikipedia;
  public
    property Service: TServices read FService write FService;
    property Query: string read FQuery write FQuery;
    procedure Submit;

    function Results: TResult;
    property GetResult: TResult read Results;
      // Gibt den Titel und die Links wieder

    property GetRawHTTPResponse: string read FResponse;
    // Gibt den kompletten HTTP Response zurück
    constructor Create;
    destructor Destroy; override;
  end;

implementation

constructor TParseServices.Create;
begin
  inherited;
  Google := TGoogle.Create;
  Milw0rm := TMilw0rm.Create;
  Heise := THeise.Create;
  Gulli := TGulli.Create;
  TecChannel := TTecChannel.Create;
  Wikipedia := TWikipedia.Create;

  FFilterdLinks.Create;
  FFilterdTitles.Create;

  // [<QUERY>] als Platzhalter wird mit StringReplace ersetzt
  // Stimmen nicht alle, nur für Anschauung präsent
  Google.FQueryURL := GoogleURL;
  Milw0rm.FQueryURL := Milw0rmURL;
  Heise.FQueryURL := HeiseURL;
  Gulli.FQueryURL := GulliURL;
  TecChannel.FQueryURL := TecChannelURL;
  Wikipedia.FQueryURL := WikipediaURL;

  // Parst den Content
  with Google do
  begin
    FPatternTitle.FBegin := ''; // Pattern kommen noch :)
    FPatternTitle.FEnd := '';
    FPatternLink.FBegin := '';
    FPatternLink.FEnd := '';
  end;

  with Milw0rm do
  begin
    FPatternTitle.FBegin := '';
    FPatternTitle.FEnd := '';
  end;

  with Heise do
  begin

  end;

  with Gulli do
  begin

  end;

  with TecChannel do
  begin

  end;

  with Wikipedia do
  begin
    FPatternTitle.FBegin := '<h1 id="firstHeading" class="firstHeading">';
    // Titel <h1 id="firstHeading" class="firstHeading">Titel</h1>
    FPatternTitle.FEnd := '</h1>';
    FPatternArticle.FBegin := '

';
    // Content

...</p><table id="toc" class="toc">
    FPatternArticle.FEnd := '</p><table id="toc" class="toc">';
  end;
end;

destructor TParseServices.Destroy;
begin
  Google.Free;
  Milw0rm.Free;
  Heise.Free;
  Gulli.Free;
  TecChannel.Free;
  Wikipedia.Free;

  FFilterdLinks.Free;
  FFilterdTitles.Free;
  inherited;
end;

procedure TParseServices.Submit;
begin
  case Service of
    svGoogle:
      begin
        Google.Parse;
      end;
    svMilw0rm:
      begin

      end;
    svHeise:
      begin

      end;
    svGulli:
      begin

      end;
    svTecchannel:
      begin

      end;
    svWikipedia:
      begin

      end;
  end;
end;

function TGoogle.Parse: TResult;
var
  Titles: TStrings;
  Links: TStrings;
begin
  Titles := TStringList.Create;
  Links := TStringList.Create;
  // ToDo: FQueryURL wird aufgerufen und die Anwort in FResponse gespeichert
  // Dann wird mitPos, PosEx, Copy geparst bis Titel und Links gefiltert sind

  Titles.Add('ATitle');
  Links.Add('ALink');
  Parse.Title := Titles;
  Parse.Link := Links;

  Links.Free;
  Titles.Free;
end;

function TParseServices.Results: TResult;
begin
  Results.Link := FFilterdLinks;
  Results.Title := FFilterdTitles;
end;

end.
  Mit Zitat antworten Zitat
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#2

Re: Aufbau logisch und korrekt?

  Alt 15. Jan 2010, 21:47
Ich würde es vermeiden, die Unterscheidung über case-Strukturen zu regeln. Das führt dazu, dass du an zig Stellen etwas verändern musst, sobald du eine weitere Seite hinzufügen willst, und führt zu unübersichtlichem Code. Leite stattdessen alle spezialisierten Seiten-Klassen von einer Basisklasse ab und biete die Methoden über ein einheitliches Interface an.

Das Strategie-Pattern ist wahrscheinlich, was du suchst.
  Mit Zitat antworten Zitat
ChEeTaH

Registriert seit: 12. Jan 2009
49 Beiträge
 
Delphi XE2 Architect
 
#3

Re: Aufbau logisch und korrekt?

  Alt 15. Jan 2010, 21:55
Danke für die Antwort.
Könntest du mir dazu ein Delphi Beispiel geben? Ich bin leider (noch) kein ausgebildeter Informatiker
Edit: Wäre das hier eine Implementation?
  Mit Zitat antworten Zitat
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#4

Re: Aufbau logisch und korrekt?

  Alt 15. Jan 2010, 23:11
Zitat von ChEeTaH:
Ich bin leider (noch) kein ausgebildeter Informatiker
Ich auch nicht

Aber ich habe mir jetzt deinen Quellcode noch einmal genauer angesehen, und dabei ist mir aufgefallen: Wozu brauchst du überhaupt TParseServices?

Eine sinnvolle, logische Klassenstruktur sähe für mich so aus:
Delphi-Quellcode:
uses
  contnrs; // für TObjectList

type

  TSearchResult = class
  private
    FTitle, FLink: string;
  public
    property Title: string read FTitle write FTitle;
    property Link: string read FLink write FLink;
  end;

  TSearchResultList = class(TObjectList)
  private
    function GetItem(Index: integer): TSearchResult;
    procedure SetItem(Index: integer; Item: TSearchResult);
  public
    property Items[index: integer]: TSearchResult read GetItem write SetItem; default;
    function Add(Item: TSearchResult): integer; override;
    { ... }
  end;

  TSearchProvider = class
  private
    FResults: TSearchResults;
    FQuery: string;
  protected
    function BuildRequestURL(Query: string): string; virtual; abstract;
    procedure Parse(Content: string); virtual; abstract;
  public
    property Results: TSearchResultList read FResults;
    property Query: string read FQuery write FQuery;
    procedure Submit;

    constructor Create;
    destructor Destroy; override;
  end;

implementation

{ TSearchProvider }

constructor TSearchProvider.Create;
begin
  inherited;
  FResults := TSearchResultList.Create(True);
end;

constructor TSearchProvider.Destroy;
begin
  FResults.Free;
end;

procedure TSearchProvider.Submit;
var
  Content: string;
begin
  Content := HTTP_GET(BuildRequestURL(FQuery)); // ausgedachte Funktion... konkrete umsetzung überlasse ich dir

  Results.Clear;
  Parse(Content);
end;

{ TSearchResultList }

function TSearchResultList.GetItem(index: integer): TSearchResult;
begin
  Result := TSearchResult(inherited GetItem(index));
end;

procedure TSearchResultList.SetItem(index: integer; Item: TSearchResult);
begin
  inherited SetItem(index, Item);
end;

function TSearchResultList.Add(Item: TSearchResult);
begin
  Result := inherited Add(Item);
end;
Eine konkrete Implementierung eines bestimmten Searchproviders könnte dann so aussehen:
Delphi-Quellcode:
type
  TGoogle = class(TSearchProvider)
  protected
    function BuildRequestURL(Query: string): string; override;
    procedure Parse(Content: string); override;
  end;

implementation

function TGoogle.BuildRequestURL(Query: string): string;
begin
  Result := Format('http://google.de/?q=%s', [Query]);
end;

procedure TGoogle.Parse(Content: string); override;
var
  SearchResult: TSearchResult;
begin
  // Suchergebnisse in Quellcode suchen...

  SearchResult := TSearchResult.Create;
  SearchResult.Title := '...';
  SearchResult.Link := '...';
  Results.Add(Searchresult);

  // ...
end;
Und ein Aufruf dann so:
Delphi-Quellcode:
var
  SearchProvider: TSearchProvider;
  i: integer;
begin
  SearchProvider := TGoogle.Create;
// SearchProvider := THeise.Create;
// SearchProvider := TGulli.Create;
  SearchProvider.Query := 'delphi forum';
  SearchProvider.Submit;
  for i := 0 to SearchProvider.Results.Count -1 do
  begin
    WriteLn(Format('Titel: %s; Link: %s',
      [SearchProvider.Results[i].Title,
       SearchProvider.Results[i].Link]));
  end;
  SearchProvider.Free;
end;
Nach dem Schema von TGoogle kannst du dir auch für alle anderen Seiten entsprechende Suchprovider erstellen.

Bitte beachte: Dieser Code wurde im Beitragseditor getippt und enthält sicher ein paar Fehlerchen - macht aber auch nix, schließlich geht es eher um die grobe Struktur.

[edit]
Zitat von ChEeTaH:
Edit: Wäre das hier eine Implementation?
Da es in großen Lettern in der Überschrift steht, wäre das anzunehmen, ja
[/edit]
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:17 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz