En opfølgning på et andet spørgsmål ( At tage en designbeslutning om læsning af modeldata fra en inputfil ).
Jeg ønsker at stille et andet spørgsmål angående byggeri eller fabriksmønster. (Jeg læste, at builder er mere kompleks end fabrik, og jeg behøver muligvis ikke bruge builder indtil videre). Så her er de data, jeg skal læse:
TABLE: "DEGREES OF FREEDOM" X=Yes Y=Yes Z=Yes R1=Yes R2=Yes R3=Yes TABLE: "ANALYSIS OPTIONS" Solver=Advanced SolverProc=Advanced TABLE: "COORDINATE SYSTEMS" Name=GLOBAL Type=Cartesian X=0 Y=0 Z=0 TABLE: "GRID LINES" CoordSys=GLOBAL AxisDir=X GridID=A XRYZCoord=-720 LineColor=Gray8Dark Visible=Yes CoordSys=GLOBAL AxisDir=X GridID=B XRYZCoord=-432 LineColor=Gray8Dark Visible=Yes CoordSys=GLOBAL AxisDir=X GridID=C XRYZCoord=-144 LineColor=Gray8Dark Visible=Yes CoordSys=GLOBAL AxisDir=X GridID=D XRYZCoord=144 LineColor=Gray8Dark Visible=Yes CoordSys=GLOBAL AxisDir=X GridID=E XRYZCoord=432 LineColor=Gray8Dark Visible=Yes CoordSys=GLOBAL AxisDir=X GridID=F XRYZCoord=720 LineColor=Gray8Dark Visible=Yes ...
Der er mange flere tabeller som disse. Nogle tabeller har forhold mellem forældre og børn (hvert koordinatsystem har sin egen gitterlinje). Jeg har lavet strukturer, der repræsenterer hver tabel, som denne:
struct ActiveDOF { bool Ux; bool Uy; bool Uz; bool Rx; bool Ry; bool Rz; }; struct GridLine { enum Direction{X, Y, Z}; enum Type{PRIMARY, SECONDARY}; enum Location{START, END}; std::string coodSystem; Direction direction; std::string gridID; float XRYZ; Type lineType; QColor color; bool visible; Location bubleLoc; bool allVisible; float bubleSize; }; struct CoordinateSystem { std::string name; std::string type; QVector3D center; // center x, center y, cetner z QVector3D about; // aboutx, about y, about z std::vector<GridLine> gridLines; };
disse datastrukturer er indarbejdet i modelklassen, hvilket vil skabe en enorm klasse, da der er 50 ulige datastrukturer som denne:
class Model { private: ActiveDOF activeDOF; CoordinateSystem coordinateSystem; .... public: Model() {} ... }
hver tabel skal have sin indstillingsmetode og få metoden. Dette design bekymrer mig, for hvis jeg beslutter at ændre det, bliver det meget tidskrævende. Jeg sætter pris på ethvert forslag. Jeg tror, at oplysningerne her også vil sætte det tidligere spørgsmål i bedre lys.
Nu ved jeg ikke, hvor bygherren eller fabriksmetoden skal gå i betragtning af situationen. Jeg kiggede på nogle kode- og UML-diagrammer, men jeg kunne ikke forstå, hvordan jeg implementerede fabrikken, eller bygherren at lave strukturer, der kræves til mit design. Jeg er nødt til at have adgang til hver tabel ved navn, fordi de muligvis kan ændres inde i modellen, så for tiden undgår jeg at gøre hver af dem til en underklasse af en virtuel baseklasse, så jeg kan gemme dem i en container.
Er det også fornuftigt, at jeg i stedet for at erklære en forekomst af datastrukturen skal holde en markør til dem? hvis alle datastrukturer er afledt af en virtuel baseklasse kaldet Record, så bliver modellen sådan:
class Model { private: ActiveDOF* activeDOF; CoordinateSystem* coordinateSystem; .... std::Vector<Record*> data; public: Model() {} ... }
Jeg synes, det er ekstra arbejde at allokere, fjerne hukommelse til dem, men det kan hjælpe med at administrere dataene og fortsætte med at skrive ekstra? Har jeg ret i at antage det?
Kommentarer
Svar
Du prøver at løse et dataadgangsproblem, og det kræver en dataadgangsløsning.
Lad os først undersøge dine foreslåede løsninger, og hvorfor de ikke løser de problemer, du har.
Fabriksmønsteret
Fabriksmønsteret (også kaldet Fabriksmetodemønsteret) er nyttigt, når du vil bruge polymorfisme, og du ønsker at adskille objektkonstruktion helt fra implementeringsklasser.
I klassebaseret programmering fabriksmetodemønsteret er et oprettelsesmønster der bruger fabriksmetoder til at håndtere problemet med at oprette objekter uden at skulle specificere nøjagtig klasse af det objekt, der oprettes. Dette gøres ved at opretter objekter ved at kalde en fabriksmetode — enten angivet i en grænseflade og implementeret af underordnede klasser eller implementeret i en basisklasse og eventuelt tilsidesat af afledte klasser — snarere end ved at kalde en konstruktør .
(fremhævelse, min)
Og længere nede uddybes det de problemer, dette mønster løser:
Fabriksmetodens designmønster løser problemer som:
- Hvordan kan et objekt oprettes så underklasser kan omdefinere hvilken klasse der skal instantieres?
- Hvordan kan en klasse udsætte instantiering til underklasser?
De problemer, du beskriver i dit spørgsmål, adskiller sig fra disse. Du har ikke at gøre med underklasser eller polymorfisme. Fabriksmønsteret er ikke en løsning.
Byggemønsteret
Byggemønsteret (fra Wikipedia ):
Builder er et designmønster designet til at give en fleksibel løsning på forskellige objektskabelsesproblemer i objektorienteret programmering. Hensigten med Builder-designmønsteret er at adskille konstruktionen af et komplekst objekt fra dets repræsentation.
(fremhævelse, mine)
Her ser vi igen en uoverensstemmelse mellem det problem, du beskriver, og den tilsigtede anvendelse af dette mønster.
Builder-designmønsteret løser problemer som:
- Hvordan kan en klasse (den samme byggeproces) skabe forskellige repræsentationer af en komplekst objekt ?
- Hvordan kan en klasse, der inkluderer oprettelse af en komplekst objekt forenkles?
(fremhævelse, mine)
Nøglen her er konstruktionen af et objekt (et objekt = 1 objekt) er komplekst. Dette kan skyldes et stort antal konstruktørargumenter eller på grund af kompleksiteten ved at samle dets afhængigheder.
Hver enkelt struktur eller klasse er individuelt ret enkel, så bygmønsteret passer heller ikke godt.
Dataadgangsmønstre (løsningen)
De problemer, du faktisk prøver at løse, er, hvordan du udfører dataadgang, og du leder muligvis efter en Dataadgangsobjekt .
I computersoftware er et dataadgangsobjekt (DAO) er et objekt, der giver en abstrakt grænseflade til en eller anden type database eller anden persistensmekanisme. Ved at kortlægge applikationsopkald til persistenslaget , DAO giver nogle specifikke datafunktioner uden at udsætte detaljer om databasen.
I dit tilfælde skal du udskifte “database” med “tekstfil”. Et relateret designmønster er Repository Design Pattern , som deler dataadgang i 3 hovedløsninger:
- Repository — den offentlige grænseflade til “dataadgangs ting”
- Gateway — ved, hvordan man kan tale med en Oracle-database eller læse / skrive til en tekstfil. Dette vil omfatte serieisering af objekter og strukturer til SQL eller det dataformat, der forventes i tekstfilen.
- Fabrik — kortlægger data, der returneres af gatewayen til objekterne og strukterne brugt af resten af din applikation
Ejerskab af hukommelse
Da du ikke har fordelen / begrænsningen af automatisk styring af hukommelse, ejerskab af hukommelsen allokeret til disse objekter og strukturer er bestemt et problem. Her skal du træffe en beslutning:
- Er dataadgangsobjektet ansvarligt for at rydde op i denne hukommelse?
- Er dataadgangsobjektet forventer, at den, der ringer op (klientkode), tager ansvar for at frigøre denne hukommelse?
Hvis dataadgangsobjektet oprettes, når applikationen starter, og lever, indtil applikationen lukkes, er datatilgangen objekt kan overtage ejerskabet af denne hukommelse.
Hvis dataadgangsobjektet oprettes efter behov og derefter bortskaffes, skal klientkode sørge for, at denne hukommelse er ryddet ned op.
Definer dette i kommentarerne eller dokumentationen til dataadgangsobjektet, og håndhæv dette i kodegennemgang.
Kommentarer
- Jeg kan godt lide denne tilgang. Ser meget mere fleksibel ud. Alt andet, jeg beder om, vil afsløre min uvidenhed om sagen. Skal jeg selv implementere DAO? Som jeg forstår det, skal jeg skrive Gateway and Factory? Er Gateway det samme som bro-GOF-mønster?
- Jeg vil sige, at gatewayen i depotmønsteret er en anden variation af bromønsteret. Faktisk ser det ud til, at grundlaget for depotmønsteret er et mere organiseret og koordineret bromønster, der specifikt er fokuseret på dataadgang. Og ja, du ‘ vil sandsynligvis være nødt til at skrive disse komponenter selv.
- efter de links, du indsendte, kom jeg til da.wikipedia.org/wiki/ODB_(C%2B%2B) , Hvordan denne ODB passer ind i billedet? Jeg kan skrive et program til at konvertere min tekstinput til sqllite og derefter bruge ODB til persistens? er denne lyd? Jeg må sige, at jeg bare snublede over ODB og så på to eksempler, så dette er ikke en informeret kommentar.
- Hjælp til skrivning af kode er uden emne for dette websted, men jeg ‘ er sikker på at du kan konvertere teksten til sqlite og bruge et eksisterende bibliotek.
Svar
En bygmester ville “bygges” inde i en fabriksunparent (metode) og derved læse en tekstfil, du ville skrive 1 fabrik med en metode til at læse den nævnte fil. Nu, hvis du har brug for trinvist at opbygge din model ud fra de data, du læser (tænk indlejrede data), ville bygmønsteret inde i fabriksmetoden tjene dig godt. Imidlertid er en enkelt model sandsynligvis tilstrækkelig til at indlæse dine data i.
Kommentarer
- Nogle pseudokoder kan være meget nyttige at høre. Jeg har aldrig brugt fabriks- eller bygningsmønstre før.
Svar
I betragtning af størrelsen og kompleksiteten af din struktur, en bygherre virker mest passende, især hvis din model er (eller kan gøres) uforanderlig. Du bliver nødt til at acceptere en tæt sammenkobling mellem bygherren og modellen, men det er besværet værd, især hvis du skal bygge modeller flere steder. En bygherre giver dig også mulighed for at indkapsle validering.
Hvis din model imidlertid kan ændres og kun oprettes ét sted, så er en fabrik muligvis mere passende og hensigtsmæssig, og YAGNI kommer i spil.
Som svar på dit andet spørgsmål , skal du aldrig gemme rå pointer i C ++. Faktum er, at std::unique_ptr
ikke har nogen ulemper, og det bagatelliserer objektdestruktion. Når denne vektor går ud af omfanget, frigør den ikke hukommelsen, referencer som skrevet, men med en unik_ptr ville det.
Jeg ville oprette en vektor til store mængder gentagne elementer, især hvis mængden sandsynligvis vil ændre sig, men for mellemstore komponenter, der aldrig deles, kan du lige så godt inkludere dem direkte i strukturen.
Model
-klassen (eller forskellige afledninger af en fælles basisklasseModelBase
ellerIModel
), og du vil centralisere beslutningen om, hvilken konkret afledning der bliver instantieret. Jeg ser ‘ ikke dette problem i dit spørgsmål, så hvad ‘ er din idé bag at bruge en fabrik her?