AGB  ·  Datenschutz  ·  Impressum  







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

Probleme mit selbst erstellter Klasse

Ein Thema von XiONLuNiX · begonnen am 5. Jun 2005 · letzter Beitrag vom 7. Jun 2005
Antwort Antwort
XiONLuNiX

Registriert seit: 5. Jun 2005
3 Beiträge
 
#1

Probleme mit selbst erstellter Klasse

  Alt 5. Jun 2005, 08:16
Hallo,

erstmal entschuldigung für die schlechte Überschrift, aber ich weis wirklich nicht wie ich mein Problem betiteln soll.

Es geht um folgendes, in der Schule lerne ich zur Zeit Delphi und wir sollten eine (Warenhaus-)Kasse simulieren.
Dazu sollte eine Schlange(FIFO, TSchlange) als Klasse erzeugt werden, welche dann Kunden(TKunde) Verwaltet.
Die Kunden werden vom Hauptformular in bestimmten Abständen erzeugt und von Zeit zur Zeit werden die Kunden "bedient"
indem ihrem Warenkorb ein Gegenstand entnommen wird und "gescannt" wird (Verringerung der TKunde-Variable "Anzahl" um 1).
Das ganze wird in einer ListBox dargestellt.
Es sollte dann so ablaufen, dass wenn der Kunde keinen Gegenstand mehr im Warenkorb hat (Anzahl = 0) der Kunde "bezahlt" (destroy) und der nächste Kunde bedient wird.

Bis dahin bin ich leider erst gar nicht gekommen. Bei mir tritt nämlich folgender Fehler auf:
Anstatt, dass ein neuer Kunde erzeugt und in die Schlange eingereiht wird (enqueue), wird das Aktuelle Element manipuliert.

Ich habe schon ziemlich viel Zeit darauf verbracht den Fehler zu finden. Doch weder durch meinen Lehrer noch durch mich konnte der Fehler behoben werden.

Ich habe mien Programm angehängt.

Ich hoffe, dass ihr mir helfen könnt.

Vielen Dank

>X!<
Angehängte Dateien
Dateityp: zip schlange_138.zip (10,8 KB, 11x aufgerufen)
  Mit Zitat antworten Zitat
marabu

Registriert seit: 6. Apr 2005
10.109 Beiträge
 
#2

Re: Probleme mit selbst erstellter Klasse

  Alt 5. Jun 2005, 13:53
Hallo,

ich habe mir dein Projekt herunter geladen. Am Quelltext erkenne ich, dass du wirklich noch nicht viel programmiert hast, aber da sind auch noch fundamentale Fehler. Ich habe dein Programm einfach mal gestartet und mir das Ergebnis angesehen. Also das Anstellen an der Schlange scheint auf den ersten Blick zu funktionieren, die Kunden werden immer mehr, der Kassierer kommt einfach nicht nach.

Wenn der Sinn der Übung darin besteht, eine FIFO-Struktur zu implementieren (die Klasse Contnrs.TQueue kann alles was du brauchst), dann solltest du das auch tun, bevor du zu Kunden und Kasse übergehst. Für die FIFO-Struktur kannst du wählen:
  • einfach verkettete Liste
  • array
Du hast dich für die einfach verkettete Liste entschieden. Dann muss der Zeiger auf den Nachfolger aber Bestandteil der Struktur sein, die du in der Liste verwalten willst - bei dir gibt es statt dessen eine globale Variable "Nach". Wenn das eine Weile funktioniert, dann ist das Glückssache.

Grüße vom marabu
  Mit Zitat antworten Zitat
XiONLuNiX

Registriert seit: 5. Jun 2005
3 Beiträge
 
#3

Re: Probleme mit selbst erstellter Klasse

  Alt 5. Jun 2005, 18:26
Hallo,

erstmal vielen Dank für die Mühe.
Dass alle Variablen, die in ner Klasse unter var stehen, global sind wusste ich bisher nicht.
Ausserdem wurde uns die einfach verkettete Liste vorgegeben, wobei mir arrays eigentlich lieber sind.

Du hast fundamentale Fehler erwähnt. Könntest du das bitte ein wenig konkretisieren?!
Da ich noch am Anfang mit Delphi stehe und meine Begegnungen mit Delphi fast ausschließlich
nur theoretischer Natur waren (also, lesen, verstehen, im Unterricht wiedergeben),
bin ich grad erst dabei mir praktische Erfahrung anzueignen.
Wohin das führt, hast du ja gesehen


>X!
  Mit Zitat antworten Zitat
marabu

Registriert seit: 6. Apr 2005
10.109 Beiträge
 
#4

Re: Probleme mit selbst erstellter Klasse

  Alt 5. Jun 2005, 20:13
Der fundamentale Fehler schlechthin ist die Sache mit den globalen Variablen Nach und Anzahl. Anzahl gehört eigentlich zum Gedächtnis deines Kunden-Objektes. Mit dem Verweis auf den Nachfolger ist das allerdings so eine Sache. Der Grad der Entkopplung deiner Klassen bestimmt wo dieser Verweis unterzubringen ist.

Denkbar sind folgende Ansätze:

(1) Deine Queue ist spezifisch und kann nur Objekte einer bestimmten Klasse verwalten.
(2) Deine Queue ist generisch und kann Objekte einer beliebigen Klasse verwalten.
(2.1) Die Klasse TKunde ist Nachfahre einer speziellen Klasse TQueueItem.
(2.2) Die Klasse TQueueItem enthält einen Verweis auf ein Kunden-Objekt.

Ich favorisiere Ansatz (2) und bei deiner Aufgabe dürften die beiden dort unterschiedenen Varianten beide problemlos umsetzbar sein.

Delphi-Quellcode:
// Variante (2.1)

type
  TQueueItem = class
  private
    FNext: TQueueItem;
  public
    property Next: TQueueItem read FNext write FNext;
  end;
  
  TKunde = class(TQueueItem)
  private
    FAnzahl: integer;
  public
    constructor Create(anzahl: integer);
    procedure Auflegen; // Einen Artikel zum Erfassen geben
    property Anzahl: integer read FAnzahl; // write nur intern
    property Naechster: TKunde read FNext;
  end;
Delphi-Quellcode:
// Variante (2.2)

type
  TQueueItem = class
  private
    FNext: TQueueItem;
    FData: TObject;
  public
    consturctor Create(data: TObject);
    property Data: TObject read FData;
    property Next: TQueueItem read FNext write FNext;
  end;
  
  TKunde = class
  private
    FAnzahl: integer;
  public
    constructor Create(anzahl: integer);
    procedure Auflegen; // Einen Artikel zum Erfassen geben
    property Anzahl: integer read FAnzahl; // write nur intern
  end;
Früher oder später solltest du dir angewöhnen abstrakte Klassen (Queue) und solche aus deinem Aufgabenfeld (Kunde, Kasse) voneinander zu trennen. Hier noch ein Code-Schnippsel für TQueue:

Delphi-Quellcode:
  TQueue = class
  private
    FHead: TQueueItem;
    FTail: TQueueItem;
  public
    function Add(qi: TQueueItem): TQueueItem;
    function Remove: TQueueItem;
    property Head: TQueueItem read FHead;
  end;
Ein anderer Fehler ist deine Verwendung von Randomize(). Diese Prozedur dient eigentlich dazu dem Pseudo-Zufallszahlen-Generator einen bestimmten Seed-Wert zu verpassen, damit er eine reproduzierbare Folge von Zufallszahlen erzeugt. Brauchst du eigentlich nicht wirklich - schon gar nicht im Konstruktor deiner Kunden-Klasse.

Bevor ich deine Hausaufgaben jetzt ganz erledige warte ich lieber mal darauf, was du so zu Stande bringst.

marabu
  Mit Zitat antworten Zitat
XiONLuNiX

Registriert seit: 5. Jun 2005
3 Beiträge
 
#5

Re: Probleme mit selbst erstellter Klasse

  Alt 6. Jun 2005, 19:00
Also, eigentlich kriegen wir die Deklarationen aus nem Buch und müssen die Methoden dann nur "füllen",
was manchmal ziemlich in die Hose geht, da die Methoden kaum beschrieben werden und die Namen auch nicht gerade aussagekräftig sind.
Ich hab versucht die Kassen so selbstständig wie möglich zu machen und das ist das Ergebnis:

Delphi-Quellcode:
unit mKasse;

interface
        uses Classes, StdCtrls, ExtCtrls, mKunde;
 type TSchlange = class(TObject)
        private
         fAktuell,fEnde :TKunde;
         TimKunde, TimBedienung: TTimer;
         fLstKasse: TListBox;
         function IsEmpty: boolean; virtual;
         procedure TimKundeTimer(Sender:TObject);
         procedure TimBedienungTimer(Sender:TObject);
         procedure Verwaltung(P: boolean); virtual;
        public
         constructor Create(List: TListBox); virtual;
         procedure Enqueue(Elem: TKunde); virtual;
         procedure Dequeue; virtual;
         property Element: TKunde read fAktuell;
         property Ende: TKunde read fEnde;
         property Offen: Boolean write Verwaltung;
         end;


implementation
constructor TSchlange.Create(List: TListBox);
begin
    fLstKasse := List;
    TimKunde := TTimer.Create(nil);
    With TimKunde do begin
          Interval := 1000;
          Enabled := false;
          OnTimer := TimKundeTimer;
          end;

    TimBedienung := TTimer.Create(nil);
    With TimBedienung do begin
          Interval := 250;
          Enabled := false;
          OnTimer := TimBedienungTimer;
          end;
end;

procedure TSchlange.Enqueue(Elem: TKunde);
var SAnzahl : String;
 begin
        if not self.IsEmpty then
                Ende.Nach := Elem
            else
                fAktuell := Elem;
        fEnde := Elem;

        Str(fEnde.Anzahl,SAnzahl);
        fLstKasse.AddItem(SAnzahl,self);
 end;

procedure TSchlange.Dequeue;
var temp: TKunde;
 begin
      if not self.IsEmpty then begin;
         temp := fAktuell;
         fAktuell := temp.Nach;
         temp.Destroy;
         if fAktuell = nil then fEnde := nil;
      end;
 end;

function TSchlange.IsEmpty: boolean;
 begin
      If fAktuell <> nil then IsEmpty := false
                        else IsEmpty := true;
 end;

procedure TSchlange.TimKundeTimer(Sender:TObject);
begin
   Enqueue(TKunde.Create);
end;

procedure TSchlange.TimBedienungTimer(Sender:TObject);
var num: string;
begin
        if not IsEmpty then begin
         fAktuell.Gescannt;
         fLstKasse.Items.Delete(0);
         if fAktuell.Anzahl = -1 then Dequeue
                                else begin
                                     str(fAktuell.Anzahl,num);
                                     fLstKasse.Items.Insert(0,num);
                                 end;
         end;
         if (IsEmpty and (TimKunde.Enabled = false)) then TimBedienung.Enabled := false;
end;

procedure TSchlange.Verwaltung(P: boolean);
begin
  TimKunde.Enabled := P;
  if p = true then TimBedienung.Enabled := p;
end;

end.
Delphi-Quellcode:
unit mKunde;

interface
 type
     TKunde = class(TObject)
      private
       fanzahl :integer;
       fNach : TKunde;
      public
       constructor Create; virtual;
       procedure Gescannt;
       property Anzahl: Integer read fAnzahl;
       property Nach: TKunde read fNach write fNach;
      end;


implementation
 constructor TKunde.Create;
  begin
   inherited create;
   randomize;
   fanzahl := random(9) +1
  end;


  procedure TKunde.Gescannt;
   begin
    fanzahl := fanzahl -1;
   end;


end.
Die Kasse stellt so gesehen selber Kunden an und bearbeitet diese,
so dass das Formular nur die ListBox bereitstellen muss.
Es funzt, aber ich schätze mal, dass die Lösung nicht gerade elegant ist.
  Mit Zitat antworten Zitat
marabu

Registriert seit: 6. Apr 2005
10.109 Beiträge
 
#6

Re: Probleme mit selbst erstellter Klasse

  Alt 7. Jun 2005, 18:51
Ich kann jetzt nicht genau erkennen, was Vorgabe ist und nicht verändert werden darf. Du sagst auch, dass dein Code funktioniert. Deshalb gebe ich nur noch ein paar zaghafte Hinweise.

Denke an das, was ich dir zu Randomize geschrieben habe. Du kannst diese Funktion einfach weglassen. Nur wenn du eine Testreihe öfter wiederholen willst, solltest du die Initialisierung mit identischem Seed-Wert an geeigneter Stelle vornehmen - z.B. vor dem Start der message pump im Projektquelltext.

Deine Timer sind ganz gewiss keine Eigenschaften einer Kasse, sondern eigentlich nur Hilfsmittel für die Ablaufsteuerung. Ich würde die Timer bei der Form ansiedeln. Noch besser wäre auf sie zu verzichten und die Erzeugung von neuen Kunden und den Vorgang des Abkassierens über Buttons interaktiv zu steuern.

Dass die Kasse selbst ihre neuen Kunden erzeugt und am Ende der Warteschlange anstellt, ist nicht sehr realistisch - auch wenn es funktionieren sollte. Da wäre eine Kunden-Factory der bessere Ansatz, aber ob der in deinem Buch besprochen wird? Wohl eher nicht.

Ist dir eigentlich schon aufgefallen, dass du gar keine Klasse TKasse hast?

Gescannt klingt so, als ob dem Kunden vom Kassierer mitgeteilt wird, dass ein Artikel erfasst wurde. Hier wie schon beim Anstellen sehe ich die aktive Rolle eher beim Kunden. Nicht der Kassierer nimmt sich einen Artikel aus dem Warenkorb des Kunden, sondern der Kunde legt einen Artikel zum Scannen auf.

Die meisten Kopfschmerzen bei deinem Projekt machen mir die Mängel im Entwurf, aber wenn das Vorgaben aus deinem Buch sind, wirst du wohl am besten so weiter machen.

Viel Erfolg

marabu
  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 04:32 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