Poprawna hierarchia klas (OOP)

0

Witam, mam problem z zapisem hierarchi mojej klasy. Klasa i hierarchia obiektów ma być zgodna z naturą i jest to przykład który ma mi pomóc zrozumieć zapis obiektów i zależności między nimi w OOP. Chcę aby każde utworzone "drzewo" miało tablice elementow "owoc" któro miało by tablice elementów "robak". Oto kilka moich prototypów :

  1. Tutaj zapisałem jedynie 3 różne klasy, niestety nie udało mi się uzyskać hierarchi. Jedynie dziedzicze z elementu nadrzędnego co wydaje mi się bezcelowe. Programista któy miał by używać takiej klasy musi sam dopilnować aby nie pomieszać przynależności owoców do drzew oraz robaków do owoców (bez sensu).
 type
  TDrzewo = class
    wysokosc : integer;
    wiek : integer;
    typ : string;

    iloscOwocow : integer;
  
  //f i p 
  constructor Create(wysokoscD, wiekD : integer; typD : string);
  destructor Destroy; override;   
  end;

 type
  TOwoc = class(TDrzewo)
    typ : string;
    waga : double;

    iloscRobakow : integer;
  //f i p
  constructor Create(wagaO : integer; typO : string);
  destructor Destroy; override; 
  end;
    
type
  TRobak = class(TOwoc)
    typ : string;
    waga : double; 
    
  //f i p
  constructor Create(wagaR : integer; typR : string);
  destructor Destroy; override; 
end;
  1. Podejście drugie, od szczegółu do ogółu. Wydaje mi się że za dużo konstruktorów. Nie potrzebnie dziedzicze, ale za to działają mi tablice i mogę je zadeklarować co w kolejnym przykładzie nie jest możliwe.
  type
  TRobak1 = class
  public
    typ : string;     
    waga : double; 
    
  //f i p
  constructor Create(wagaR : integer; typR : string);
 destructor Destroy; override; 

      type
      TOwoc1 = class(TRobak1)
      public   
        typ : string;
        waga : double;

        iloscRobakow : integer;
        RobakiA : array of TRobak1;
      //f i p
      constructor Create(wagaO : integer; typO : string);
      destructor Destroy; override; 


          type
          TDrzewo1 = class(TOwoc1)
            public
            wysokosc : integer;
            wiek : integer;
            typ : string;

            iloscOwocow : integer;
            OwoceA : array of TOwoc1;
          //f i p 
          constructor Create(wysokoscD, wiekD : integer; typD : string);
         destructor Destroy; override;   
 
          end;
      end;
  end;
  1. Od ogółu do szczegółu. Nie mogę zadeklarować tablicy elementów z klasy podrzędnej. Zapis wydaje mi się najbardziej właściwy.
type
TDrzewo2 = class
public 
wysokosc : integer;
wiek : integer;
typ : string;

iloscOwocow : integer;
tab1 : array of TOwoc2;   //<--- blad
//f i p 
constructor Create(wysokoscD, wiekD : integer; typD : string);
destructor Destroy; override;
          

    type
    TOwoc2 = class
    public   
    typ : string;
    waga : double;

    iloscRobakow : integer;
    //f i p
 

                       
        type
        TRobak2 = class
        public 
        typ : string;     
        waga : double; 
    
        //f i p


          end;
      end;
  end; 

Niestety nie wiem jak rozwiązać tak prosty problem. Czy ktoś mógłby mnie naprowadzić i powiedzieć jak to miało by wyglądać. Mam w zamyśle poprawić swoje programy i napisać nowe zgodnie z OOP i to mnie bardzo blokuje.

3

Ponieważ Owoc nie jest Robakiem ani też Robak nie jest Owocem to żadne dziedziczenie Jednego po drugim nie ma sensu, więc wersje 1,2 odpadają.
Wersja 3 jest prawie sensowna, prawie ponieważ Robak może istnieć poza Owocem zaś Owoc może istnieć nie będąc na Drzewie - w związku z czym deklaracja jednej klasy wewnątrz drugiej - nie ma sensu.
Kolejnym dziwolągiem jest iloscRobakow:integer; - a mianowicie, jeżeli już masz klasę Robak to sama ilość robaków jest mało sensowna, może warto od razu stworzyć kontener.

1

Kompilator nie wywala bledu przy tym:

type
  TOwoc2 = class
  public
    typ: string;
    waga: double;

    iloscRobakow: integer;
    // f i p

  type
    TRobak2 = class
    public
      typ: string;
      waga: double;

      // f i p

    end;
  end;

type
  TDrzewo2 = class
  public
    wysokosc: integer;
    wiek: integer;
    typ: string;

    iloscOwocow: integer;
    tab1: array of TOwoc2; // <--- blad
    // f i p
    constructor Create(wysokoscD, wiekD: integer; typD: string);
    destructor Destroy; override;
  end;

Co do poprawosci, to nie wnikam

0

Czyli ewentualnie musiało by to wyglądać tak:

 type
  TRobak2 = class
  public
    typ: string;
    waga: double;
 
    // f i p
 
  end;
                       
type
  TOwoc2 = class
  public
    typ: string;
    waga: double;
 
    tab2: array of TRobak2; 
    // f i p
 
  end;
 
type
  TDrzewo2 = class
  public
    wysokosc: integer;
    wiek: integer;
    typ: string;
 
    iloscOwocow: integer;
    tab1: array of TOwoc2; 
    // f i p
    constructor Create(wysokoscD, wiekD: integer; typD: string);
    destructor Destroy; override;
  end;

Kazdy obiekt może istnieć sam sobie i w dowolnym momencie, a powiązane są ze sobą tablicami wewnątrz. Co daje też możliwość szybkiego zliczenia elementów. Czy takie rozwiązanie jest już bardziej prawidłowe? Czy sposób powiązania ze sobą elementów inaczej się realizuje? O kontenerach muszę poczytać bo nic nie wiem, to coś podobne do rekordów?

0
    iloscOwocow: integer;
    tab1: array of TOwoc2; 
  1. Po co ci iloscOwocow jak masz array of TOwoc2 ?
  2. Czemu wszystko jest publiczne?
0

Moja wiedza z oop sprowadza sie do zrobienia jednej klasy, ewnetualnie kilku, ale wydaje sie kod ok jesli chcesz wspoldzielic jakies dane bez uzywania zmiennych globalnych. Ja bym to zrobil inaczej, kwestia gustu.

0

Jasne iloscOwocow nie jest potrzebna ( nie zauważyłem tego, ale opisalem w poscie ). Publiczne dla ułatwienia. Nie zastanawiałem się specjalnie nad tym gdzie jakie dane umieścić z powodu takiego, że nie ma żadnej metody nawet :D Rozumiem to tak, że jeśli właściwość nie może być zmieniana dowolnie robię dla niej metode która obsługuje zmiane jej wartości, a ją samą daje do private. Nie bardzo czuje jeszcze jakie zmienne warto w ogóle dawać do public. Wiedzę czerpię od Pana Zelenta z YT :D

0

Dobrze rozumiesz - "Rozumiem to tak, że jeśli właściwość nie może być zmieniana dowolnie robię", jednak tego nie zrobiłeś, więc istnieje szansa stworzenia drzewa o ujemnym wieku i ujemnej wysokości.

0

Ok wkoncu zrobilem. Zeszlo tak dlugo bo machnąłem się i zamiast RobakiA[ile] := TRobak.Create(masa,'j') dałem RobakiA[ile].Create(masa,'l') i wywalało błąd.
Jeśli możecie rzucić okiem na wynik o będę wdzięczny. Dałem tablice do public bo chcę mieć dostęp do tablicy bardziej wygodny, tak bym musiał kolejną funkcję pisać (komentarz).
Jeśli jest coś co warto jeszcze tutaj dodać lub zmienić to proszę o informację.

 unit KPodejscie;

interface

////////////////////////////////////////////////////////////////////////////////
///                                                                 ROBAK
////////////////////////////////////////////////////////////////////////////////
type
  TRobak = class
  private
    typ: string;
    waga: double;
 
    // f i p
    public
    constructor Create(wagaR: double; typR: string);
    function UsunRobaka(i : integer) : boolean;
end;

////////////////////////////////////////////////////////////////////////////////
///                                                                 Owoc
////////////////////////////////////////////////////////////////////////////////
type
  TOwoc = class
  private
    typ: string;
    waga: double;
    // f i p
  public
      RobakiA: array of TRobak;      // jesli prywatne to : func PobierzR(nr : integer) : TRobak, wagaP := PobierzR(2).waga
    constructor Create( wagaO: integer;  typO: string);
    function IleRobakow() : integer;
    procedure DodajRobaka( masa : double);
    function UsunOwoc(i : integer) : boolean;
    function WagaRobakow() : double;
  end;

////////////////////////////////////////////////////////////////////////////////
///                                                                 Drzewo
////////////////////////////////////////////////////////////////////////////////
type
  TDrzewo = class
  private
    wysokosc: integer;
    wiek: integer;
    typ: string;

    // f i p
  public
      OwoceA: array of TOwoc;
    function WagaRobakowNaDrzewie() : double;
    function WszystkichRobakow() : integer;
    function IleOwocow() : integer;
    procedure DodajOwoc();
    function Rosnij(nawoz : integer) : integer;
    function Wiekk(dodaj : integer) : integer;
    constructor Create( wysokoscD, wiekD: integer;  typD: string);
    destructor Destroy; override;
  end;

implementation

////////////////////////////////////////////////////////////////////////////////
///                                                                 Procedury
////////////////////////////////////////////////////////////////////////////////
constructor TDrzewo.Create(wysokoscD, wiekD : integer; typD : string);
begin
  wysokosc := wysokoscD;
  wiek := wiekD;
  typ := typD;
end;

constructor TOwoc.Create( wagaO: integer;  typO: string);
begin
  self.waga := wagaO;
  self.typ := typO;
end;

constructor TRobak.Create(wagaR: double; typR: string);
begin
  self.waga := wagaR;
  self.typ := typR;
end;

destructor TDrzewo.Destroy;
begin
  inherited; 
end;

function TDrzewo.IleOwocow() : integer;
var
  I : integer;
begin
  Result := length(OwoceA);
end;

function TDrzewo.Rosnij(nawoz : integer) : integer;
begin
self.wysokosc :=  self.wysokosc + nawoz;
      Result := self.wysokosc ;
end;

function TDrzewo.Wiekk(dodaj : integer) : integer;
 begin
self.wiek :=  self.wiek + dodaj;
      Result := self.wiek ;
end;

function TDrzewo.WszystkichRobakow() : integer;
var
  I : integer;
begin
Result := 0;
for I := 0 to length(OwoceA)-1 do
   begin
     Result := Result + OwoceA[i].IleRobakow;
   end;
end;

function TOwoc.IleRobakow() : integer;
var
  I : integer;
begin
  Result := length(RobakiA);
end;

function TOwoc.WagaRobakow() : double;
var
  I : integer;
begin
Result := 0;
for I := 0 to length(RobakiA)-1 do
   begin
     Result := Result + RobakiA[i].Waga;
   end;
end;

function TDrzewo.WagaRobakowNaDrzewie() : double;
var
  I : integer;
begin
for I := 0 to length(OwoceA)-1 do
   begin
     Result := Result + OwoceA[i].WagaRobakow;
   end;
end;
///////////////////////////////////////////

procedure TOwoc.DodajRobaka( masa : double);
var
  k, ile : integer;
begin
  ile := length(RobakiA);
  Setlength(RobakiA,ile+1);
  RobakiA[ile] := TRobak.Create(masa,'');
end;

function TRobak.UsunRobaka(i : integer) : boolean;
var
  k : integer;
begin
   //
end;

procedure TDrzewo.DodajOwoc();
var
  k, ile,mm : integer;

begin
  ile := length(OwoceA);
  Setlength(OwoceA,ile+1);
  OwoceA[ile] := TOwoc.Create(12,'  ');
end;

function TOwoc.UsunOwoc(i : integer) : boolean;
var
  k : integer;
begin
   //
end;

end.

1 użytkowników online, w tym zalogowanych: 0, gości: 1