Ontwerp object met veel subclasses

Pagina: 1
Acties:

  • Boss
  • Registratie: September 1999
  • Laatst online: 19:31

Boss

+1 Overgewaardeerd

Topicstarter
Ik ben bezig met een ontwerp van een classmodel waarin bij een paar classes nogal wat subclasses gaan komen. Dit model gaat gerealiseerd worden in Delphi, waar ik gebruik maak van TObjectLists als 'container' class. Even de volgende vergelijking:
code:
1
2
Straat
 + Huizen

Nu heb ik volgens mij twee mogelijkheden:

Ik kan bij TStraat een TObjectList maken waarin ik de huizen zet. TStraat krijgt dan functies 'AddHuis' en 'GetHuis' etc:
code:
1
Huizen.AddHuis("Nummer 18");


De andere optie is dat ik een afgeleide maak van TObjectList: THuizenList. Hieraan hang ik de functies Add en Get etc. Vervolgens bij THuizen een property HuizenList. De functie wordt dan:
code:
1
Straat.Huizen.Add("Nummer 18")


Ik twijfel heel erg. De eerste optie beperkt het aantal zelf gemaakte classes. Op zich is dat denk ik niet iets om na te streven.

De tweede optie geeft de ontwikkelaar (die verder met mijn classemodel aan de slag gaat) meer overzicht denk ik. Zeker als er in een Straat misschien ook nog Bomen, Parkeerplaatsen en Lantarenpalen komen :) Bij de eerste optie krijg je een hele reeks functies direct onder TStraat: AddHuis, AddParkeerplaats etc. (het gaat niet alleen om de Get en Set functies, maar ook nog om een reeks specifieke functie per class). Bij de tweede optie zit dat weer netjes in de lists.

Iemand die technisch onderbouwde voorkeur heeft voor het een of het ander?

The process of preparing programs for a digital computer is especially attractive, not only because it can be economically and scientifically rewarding, but also because it is an aesthetic experience much like composing poetry or music.


  • Cuball
  • Registratie: Mei 2002
  • Laatst online: 03-02 20:14
Ik zou persoonlijk voor een simple add methode niet een eigen collectie gaan maken. Maar als je dat dan toch wil zou ik niet afleiden van je Collection maar er een Wrapper van maken (een has-a relatie ipv is-a ).

Probeer altijd composition te gebruiken ipv inheritance, als je later een ander type collectie wil gebruiken hoef je er gewoon voor te zorgen dat deze dezelfde interface als je collectie nu implementeert en dan kan je die gewoon vervangen in je code. Je bent niet meer gebonden aan 1 type collectie nu...

"Live as if you were to die tomorrow. Learn as if you were to live forever"


  • Boss
  • Registratie: September 1999
  • Laatst online: 19:31

Boss

+1 Overgewaardeerd

Topicstarter
Waarom geen inheritance? Ik heb nog niet veel gebruik gemaakt van composition, maar als ik het zo begrijp zou ik dan (uit mijn voorgaande voorbeeld) alle lantarenpalen los maken, met een verwijzing naar de straat waar ze in staan. Verwijder ik de straat, blijven de lanterenpalen staan. Ik heb toch eigenlijk liever dat ze meteen meegaan.

Ik heb nu in Delphi ongeveer het volgende:
Delphi:
1
2
3
4
5
6
7
8
TBoom= Class(TObject);
TLBomen = Class(TObjectList);
//(+functies voor get/set van TBoom)

TStraat = Class(TObject)
private
  Bomen : TLBomen
end;


TLBomen is dus een wrapper om de TObjectList zodat deze alleen objecten van het type Boom kan bevatten.

Op zich toch een nette constructie, of maak ik nu een fout?

The process of preparing programs for a digital computer is especially attractive, not only because it can be economically and scientifically rewarding, but also because it is an aesthetic experience much like composing poetry or music.


  • whoami
  • Registratie: December 2000
  • Laatst online: 21:01
Waarom geen inheritance? Ik heb nog niet veel gebruik gemaakt van composition
Eén van de OO ontwerp - guidelines is 'favor composition over inheritance'.
Natuurlijk, het moet nog bruikbaar zijn, en 'passen'. Dit wil nu niet zeggen dat je altijd in iedere situatie composition zou moeten gebruiken.
Soit.

Wat zou een THuizenList méér bieden qua functionaliteit dan een gewone TObjectList die je public maakt ?
Kan je in dit geval 'forceren' dat de Add method van een THuizenList enkel een object van het type THuis neemt ?

De AddHuis aanpak (de eerste aanpak) geeft als voordeel dat je op de een of andere manier eenvoudig een 'gecontroleerde' Add method hebt. Ik bedoel: stel dat je in een THuis een referentie bijhoudt naar de straat waarin dat huis staat, dan kan je dat makkelijk in de AddHuis method doen.

Dé enige juiste manier bestaat niet. Iedere aanpak heeft z'n voor- en nadelen. Aan jou om die aanpak te kiezen die voor jou, in deze bepaalde situatie, het beste werkt.

https://fgheysels.github.io/


  • Boss
  • Registratie: September 1999
  • Laatst online: 19:31

Boss

+1 Overgewaardeerd

Topicstarter
Kan je in dit geval 'forceren' dat de Add method van een THuizenList enkel een object van het type THuis neemt ?
Dat is dus voor mij een van de voornaamste redenen. Het model dat ik aan het maken ben gaat gebruikt worden om op basis van mijn classes te modelleren (ik ben een soort modelleer omgeving aan het maken).

Ik wil de modelleerder (die ook in Delphi gaat werken, maar dus met de door mij gedefinieerde classes) een duidelijke en overzichtelijke toolbox geven. Vandaar dat ik graag gebruik maak van de mogelijkheden die Delphi biedt in de IDE als de classes allemaal netjes gedefinieerd zijn. Op die manier kan hij niet eens compilen als er een keer een TBoom en een TLanterenpalenList wordt gestopt, zeg maar.

The process of preparing programs for a digital computer is especially attractive, not only because it can be economically and scientifically rewarding, but also because it is an aesthetic experience much like composing poetry or music.


Verwijderd

whoami schreef op woensdag 02 augustus 2006 @ 14:47:
Eén van de OO ontwerp - guidelines is 'favor composition over inheritance'.
Waarom?
Net even snel het simpele voorbeeldje uit deze link (Rectangle en Square) nagebouwd in Delphi: TSquareI inherit van TRectangle, TSquareC gebruikt composition. Ik weet wel welke ik prettiger en logischer vind, en dat is niet de laatste... ;)
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
interface

type
  TRectangle = class
  private
    FWidth: integer;
    FHeight: integer;
  public
    constructor Create(Width, Height: integer);
    procedure SetSize(Width, Height: integer);
    function GetArea: integer;
  end;

  TSquareI = class(TRectangle)
  public
    constructor Create(Size: integer); reintroduce;
    procedure SetSize(Size: integer); reintroduce;
  end;

  TSquareC = class
  private
    FRectangle: TRectangle;
  public
    constructor Create(Size: integer);
    destructor Destroy; override;
    procedure SetSize(Size: integer);
    function GetArea: integer;
  end;

implementation

{ TRectangle }

constructor TRectangle.Create(Width, Height: integer);
begin
  SetSize(Width, Height);
end;

procedure TRectangle.SetSize(Width, Height: integer);
begin
  FWidth := Width;
  FHeight := Height;
end;

function TRectangle.GetArea: integer;
begin
  Result := FWidth * FHeight;
end;

{ TSquareI }

constructor TSquareI.Create(Size: integer);
begin
  SetSize(Size);
end;

procedure TSquareI.SetSize(Size: integer);
begin
  inherited SetSize(Size, Size);
end;

{ TSquareC }

constructor TSquareC.Create(Size: integer);
begin
  FRectangle := TRectangle.Create(Size, Size);
end;

destructor TSquareC.Destroy;
begin
  FRectangle.Free;
end;

procedure TSquareC.SetSize(Size: integer);
begin
  FRectangle.SetSize(Size, Size);
end;

function TSquareC.GetArea: integer;
begin
  Result := FRectangle.GetArea;
end;
De AddHuis aanpak (de eerste aanpak) geeft als voordeel dat je op de een of andere manier eenvoudig een 'gecontroleerde' Add method hebt. Ik bedoel: stel dat je in een THuis een referentie bijhoudt naar de straat waarin dat huis staat, dan kan je dat makkelijk in de AddHuis method doen.
Wanneer je THuizenList weet bij welke TStraat 'ie hoort (1 private member, en een constructor override), dan kan 'ie dat zelf ook prima (laten) bijhouden.

  • whoami
  • Registratie: December 2000
  • Laatst online: 21:01
Ik heb ook niet gezegd dat je het altijd moet gebruiken; gebruik inheritance wanneer inheritance het beste werkt, gebruik composition als dat het beste werkt.
Zolang je een 'Is a' relatie hebt, kan je inheritance gebruiken.
Een Square is een rectangle.
Wanneer je THuizenList weet bij welke TStraat 'ie hoort (1 private member, en een constructor override), dan kan 'ie dat zelf ook prima (laten) bijhouden.
Ik bedoel dit:
(pseudo-code)
code:
1
2
3
4
5
6
7
8
9
10
class Straat
{
    private Collection HuizenList;

    public void AddHuis( Huis h )
    {
          h.Straat = this;
          HuizenList.Add (h);
    }
}

[ Voor 33% gewijzigd door whoami op 03-08-2006 23:39 ]

https://fgheysels.github.io/


Verwijderd

Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
interface

type
  THuizenList = class(TList)
  private
    FStraat: TStraat;
  public
    constructor Create(AStraat: TStraat);
    function Add(Huis: THuis): integer; override;
  end;

implementation

{ THuizenList }

constructor THuizenList.Create(AStraat: TStraat);
begin
  inherited Create;
  FStraat := AStraat;
end;

function THuizenList.Add(Huis: THuis): integer;
begin
  Huis.Straat := FStraat;
  inherited;
end;

Nu leg ik de 'intelligentie' bij de HuizenList om die straat te zetten, en een stukje intelligentie bij de Straat (die moet aan de HuizenList vertellen dat 'ie 'm aanmaakt). Beide hebben voor en nadelen, maar mijn voorkeur gaat uit naar de controle op de Add method te leggen bij de list/collection die 't betreft, en niet bij het object dat die list toevallig heeft aangemaakt.

  • Boss
  • Registratie: September 1999
  • Laatst online: 19:31

Boss

+1 Overgewaardeerd

Topicstarter
Zo te horen zijn beide dus goed te gebruiken. Mijn 'angst' was eigenlijk dat ik nu onnodig veel objecten aanmaak (voor iedere class ook een container class die alleen een override is van TObjectList). Dacht dat dat mischien slordig zou izjn of tegen een of andere basisregel in zou gaan.

Ik hou het dus bij de 2e manier: voor iedere class een eigen containerclass. Beetje meer werk, maar het wordt wel een hele mooie toolkit op die manier.

The process of preparing programs for a digital computer is especially attractive, not only because it can be economically and scientifically rewarding, but also because it is an aesthetic experience much like composing poetry or music.

Pagina: 1