WebDAV in Vista is horribly broken. Ik wil het fixen, maar ben nog steeds op zoek naar de tarball met de source...
C++ is wel crossplatform. Als vervolgens al je libs (bv: WxWidgets voor GUI, SDL/OpenGL voor tekenen, dat soort dingen) gebruikt en zorgt geen MFC of andere Windows-only libs te gebruiken, dan kun je je spel op alle systemen compileren.Parasietje schreef op dinsdag 04 juli 2006 @ 14:40:
Ik ben C++ aan het overwegen om deze nare chaos op te lossen
Een experimentele community-site: https://technobabblenerdtalk.nl/. DM voor invite code.
[ Voor 3% gewijzigd door Y0ur1 op 04-07-2006 14:56 ]
Wat zou het nadeel van een Singleton pattern zijn dan? Je hebt als het goed is maar 1 Game object.Parasietje schreef op dinsdag 04 juli 2006 @ 14:40:
Ik ben C++ aan het overwegen om deze nare chaos op te lossen, maar dat is dan weer niet cross-platform... Conclusie: ik zit hopeloos in de knoei.
Zijn er goede alternatieven voor een singleton-structuur in java, of zijn er cross-platform programmeertalen waarin pointers WEL kunnen?
Zo doe ik het zelf ook, er zijn een hele hoop dingen die je vanuit Pawn classes etc. moet kunnen bereiken. Ik gebruik voor de volgende dingen static objecten:
Gamestate (2D array voor de kaartdata, arrays voor Pawns, items en projectielen)
Resource manager (laadt alle textures, geluiden enz. en heeft een instance van alle Pawn en Tile classes, alle game-objecten refereren naar textures en geluiden in de resourcemanager, om geheugen te sparen)
Renderer (doet Direct3D dingen)
Mouse (leest de muis uit dmv. DirectInput)
Keyboard (idem voor keyboard)
Naarmate je game groter wordt, zul je meer van dit soort dingen krijgen omdat je gewoon niet alles bij elkaar kunt blijven stoppen.
[ Voor 4% gewijzigd door Not Pingu op 04-07-2006 14:58 ]
Certified smart block developer op de agile darkchain stack. PM voor info.
ik ben nou juist blij om van die pointers af te zijn.... (prog in C#)
Het is sowieso beter om de scope zo klein mogelijk te houden, voornamelijk voor de beheersbaarheid.
Fat Pizza's pizza, they are big and they are cheezy
Ik vraag me wel af of je in C++ niet exact hetzelfde gaat doen als je nu doet... Ik denk het namelijk wel...
Deze post is bestemd voor hen die een tegenwoordige tijd kunnen onderscheiden van een toekomstige halfvoorwaardelijke bepaalde subinverte plagiale aanvoegend intentioneel verleden tijd.
- Giphart
Globale variabelen kun je wijzigen, dmv access via een functie kun je ervoor zorgen dat het voor de buitenwereld slechts read-only is. Bovendien heb je extra controle over constructie/destructie en kun je later evt. aanvullende functionaliteit in je accessor kwijt.JKVA schreef op dinsdag 04 juli 2006 @ 19:05:
Ik heb altijd al iets tegen singletons gehad. Ik kan het niet zo goed onderbouwen, maar ik heb altijd een slecht gevoel bij singletons. En dat komt voornamelijk omdat het naar mijn idee niets toevoegt aan een gewone globale variabele. En als er iets is wat ik altijd probeer te vermijden, is het wel een globale variabele.
Het is sowieso beter om de scope zo klein mogelijk te houden, voornamelijk voor de beheersbaarheid.
Get/Set accessors zijn eigenlijk ook maar gewoon een manier om een member te exposen, zullen we alle members maar gelijk public gaan maken?
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Ik zie eerlijkgezegd niet in wat er tegen een singleton pattern zou zijn. Let wel ik werk met C# en heb geen ervaring met Java of C++.
Certified smart block developer op de agile darkchain stack. PM voor info.
Main.getGame().getPlayer(0).getPawns() is volgens jou een grotere omweg dan *Main->*Game->Player[0]*->*Pawns (of iets dergelijks, ik spreek geen C++)?Parasietje schreef op dinsdag 04 juli 2006 @ 14:40:
Ik wil een monopolie-spel programmeren. Een heleboel objecten moeten terug refereren naar een "Game"-object die een heleboel informatie bijhoudt. Hiervoor gebruik ik een singleton-structuur.
Idealiter zou ik dit met pointers doen. Helaas heeft Java (de taal waar ik nu in programmeer) geen ondersteuning voor pointers. Als een object veranderd moet worden, moet dit object via een hele omweg worden aangesproken (Singleton Game -> object Player -> object Pawn).
[ Voor 3% gewijzigd door Confusion op 05-07-2006 07:32 ]
Wie trösten wir uns, die Mörder aller Mörder?
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.
Volgens mij slaat de compiler beide versies plat naar een platte pointer.Confusion schreef op woensdag 05 juli 2006 @ 07:31:
[...]
Main.getGame().getPlayer(0).getPawns() is volgens jou een grotere omweg dan *Main->*Game->Player[0]*->*Pawns (of iets dergelijks, ik spreek geen C++)?
Na betaling van een licentievergoeding van €1.000 verkrijgen bedrijven het recht om deze post te gebruiken voor het trainen van artificiële intelligentiesystemen.
Beide mogelijkheden zijn zowel in Java als C++ mogelijk (afgezien van wat syntaxfouten in je C++Confusion schreef op woensdag 05 juli 2006 @ 07:31:
Main.getGame().getPlayer(0).getPawns() is volgens jou een grotere omweg dan *Main->*Game->Player[0]*->*Pawns (of iets dergelijks, ik spreek geen C++)?
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
De topicstarter klaagt dat een object dat veranderd moet worden via 'een omweg' aangesproken moet worden. Ik vraag me of waarom hij denkt dat die weg in C++ kleiner zou zijn; volgens mij lijken de wegen redelijk veel op elkaar..oisyn schreef op woensdag 05 juli 2006 @ 13:01:
Beide mogelijkheden zijn zowel in Java als C++ mogelijk (afgezien van wat syntaxfouten in je C++), dus wat je nou precies probeert te zeggen ontgaat me een beetje...
Wie trösten wir uns, die Mörder aller Mörder?
1
2
| Main.getGame().getPlayer(0).getPawns() Main.game.players[0].pawns |
1
2
| Main::getGame()->getPlayer(0)->getPawns() Main::game->players[0]->pawns |
[ Voor 7% gewijzigd door .oisyn op 05-07-2006 13:44 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Dat is omdat de topicstarter zegt dat hij het 'idealiter' met pointers zou doen en ik ging er vanuit dat hij pointers naar properties bedoelde, niet pointers naar methoden. Dat is in Java niet mogelijk, maar in C++ wel, hoewel je het, zoals je zegt, helemaal niet moet willen als je aan de tag van dit topic wilt voldoen. Maar zelfs als je pointers naar properties gebruikt, wordt de weg volgens mij niet korter..oisyn schreef op woensdag 05 juli 2006 @ 13:20:
Maar vervolgens geef je een C++ alternatief met het gebruik van variabelen ipv functies, waardoor je lijkt te suggereren dat het in Java gepast is om het met functies te doen maar in C++ met variabelen, wat uiteraard niet zo is
Kortom: ik begrijp helemaal niet wat de topicstarter denkt
[ Voor 3% gewijzigd door Confusion op 05-07-2006 13:50 ]
Wie trösten wir uns, die Mörder aller Mörder?
Verwijderd
[ Voor 27% gewijzigd door Verwijderd op 05-07-2006 16:46 ]
Heb je het nou over pointer-to-membersConfusion schreef op woensdag 05 juli 2006 @ 13:50:
[...]
Dat is omdat de topicstarter zegt dat hij het 'idealiter' met pointers zou doen en ik ging er vanuit dat hij pointers naar properties bedoelde, niet pointers naar methoden. Dat is in Java niet mogelijk, maar in C++ wel, hoewel je het, zoals je zegt, helemaal niet moet willen als je aan de tag van dit topic wilt voldoen. Maar zelfs als je pointers naar properties gebruikt, wordt de weg volgens mij niet korter.
Het is idd raar dat de topicstarter het heeft over het gemis van pointers, je kunt idd geen pointer naar een int hebben in Java, maar wat is er mis met een pointer naar een object, wat alle object variabelen standaard zijn? Wellicht is ie gewoon in de war door de . van Java waar in C++ de -> voor gebruikt wordt en het gemis van een * (dus Game ipv Game*), en denkt hij dat als je een Game instance aan een variabele assignt dat er dan een kopie wordt gemaakt?
[ Voor 3% gewijzigd door .oisyn op 05-07-2006 17:00 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Ik vermoed inderdaad dat daar het probleem zit..oisyn schreef op woensdag 05 juli 2006 @ 16:59:
[...]Wellicht is ie gewoon in de war door de . van Java waar in C++ de -> voor gebruikt wordt en het gemis van een * (dus Game ipv Game*), en denkt hij dat als je een Game instance aan een variabele assignt dat er dan een kopie wordt gemaakt?
Verwijderd
Ik weet het wel vrij zeker. Op de een of andere reden is er een hele cult aan mensen die denkt dat "Java geen pointers heeft". De waarheid is echter juist andersom:IrishMaiden schreef op woensdag 05 juli 2006 @ 17:04:
[...]
Ik vermoed inderdaad dat daar het probleem zit.
Voor objecten en arrays kent Java alleen maar pointers (m.a.w. alleen maar heap allocaties). De stack allocatie zoals we die in C++ vinden (MyObj obj; of int a[50];) is in Java niet bestaand.
Omdat je in Java geen onderscheid hoeft te maken tussen heap en stack gealloceerde objecten is dus 1 van de twee operators '.' en '->' overbodig. In Java hadden de designers ook voor '->' kunnen kiezen, maar mischien ietwat ter verwarring voor C/C++ programmeurs kozen ze voor '.'.
Gerelateerd aan dit misverstand is de onuitroeibare gedachte dat Java call-by-reference is. Vanwege het feit dat pointers in de officiele Java nomen-clature references genoemd worden denken hele volkstammen dat Java dus ook call-by-reference semantics gebruikt. Nix is echter minder waar. Java kent (voor non-remote objecten) alleen call-by-value.
Wat betreft het singleton pattern in dit geval is dat het gevoelsmatig idd niet klopt. Hoewel de meningen verschillen duidt het gebruik van singletons 90% van de gevallen op een design error. Singletons zijn soms handig voor dingen waar je er -echt- maar eentje van hebt, meestal direct gemapped naar fysieke resources.
In dit geval is er in het spel maar 1 game en zal dit wel zo blijven ook. In het algemeen kun je dit vaak niet stellen. Het kan bijvoorbeeld zijn dat je op een gegeven moment een 2de game wil instantieren waarin je de setten tot nu toe animeerd. Of mischien wil je een board naast het huidige board weergeven waarin je de speler setten wilt laten uitproberen (hangt een beetje af van wat jouw 'game' object precies is en hoe de rest in elkaar zit)
Na velen jaren in de software development te zitten heb ik vele designs van mensen zien langskomen waarin singletons gebruikt werden omdat 'je dan overal zo makkelijk bij kunt'. In de genoemde +-90% was er dan later altijd een noodzaak om een 2de instantie van het singleton object aan te maken of om de classen die er gebruik van maakte een ander object te laten gebruiken.
De bottom line is dus, gebruik alleen singletons als je weet wat je doet, en je beredeneerd hebt dat er -echt- sprake is van een singleton pattern. Ga niet zomaar singletons gebruiken omdat je ergens dan makkelijk bij kunt, omdat je het 'mooi' vind, of omdat je denkt dat Java geen pointers heeft oid.
Hier wil ik dan wel weer even op inspringen door te zeggen dat het misschien niet altijd even netjes is maar wel bloedje efficient is. Globale variabelen (wat singletons effectief zijn als je de resulterende assembly code bekijkt) kosten vrij weinig en zijn snel te accessen. Als elk object in je game referenties moet gaan houden naar verschillende systemen (Game, RenderDevice, ResourceLoader, WeetIkNietWat) kost dat meer mem, wat op z'n beurt ook weer meer cache-misses en dus tragere code oplevert. Wij hebben in onze games zo'n beetje voor elke manager een singleton (ik noem een renderer, scene manager, memory manager, sound manager, animation manager, file manager, resource manager, ...). En het werkt ook nog eens fijn omdat je niet bij het aanmaken van elke instantie een waslijst aan pointers mee hoeft te geven.Verwijderd schreef op donderdag 06 juli 2006 @ 00:08:
Na velen jaren in de software development te zitten heb ik vele designs van mensen zien langskomen waarin singletons gebruikt werden omdat 'je dan overal zo makkelijk bij kunt'. In de genoemde +-90% was er dan later altijd een noodzaak om een 2de instantie van het singleton object aan te maken of om de classen die er gebruik van maakte een ander object te laten gebruiken.
Het werkt ook goed tegen onnodige dependencies. Iemand die een character instantieert is niet geïnteresseerd in de renderer, terwijl dat object zichzelf wel moet kunnen tekenen.
Begrijp me niet verkeerd, ik ben zeker voor mooie code, maar er is ook nog gewoon zoiets als pragmatisch te werk gaan en zorgen dat je de klus klaart op een goede manier. (En je zal begrijpen dat meerdere games kunnen instantieren in ons geval allesbehalve nodig is
[ Voor 17% gewijzigd door .oisyn op 06-07-2006 02:34 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Verder moet ik zeggen dat ik het met Henk de Man eens ben. Je moet Singletons niet alleen maar gebruiken omdat het een paar method calls in je code scheelt, maar omdat je een daadwerkelijk goede reden in je design hebt om voor een Singleton te kiezen. En in mijn ervaring is die reden in de meeste gevallen ver te zoeken. Gevolg, later heb je er last van als je toch iets twee keer wilt instantieren o.i.d.
Maar goed, mijn ervaring is geen games bouwen, maar applicaties, dus misschien bekijk ik het vanuit mijn perspectief helemaal verkeerd.
Fat Pizza's pizza, they are big and they are cheezy
.oisyn schreef op woensdag 05 juli 2006 @ 16:59:
Heb je het nou over pointer-to-members. Ik gebruik in mijn codevoorbeeld geen van beiden (geen pointer-to-member-variables en geen pointer-to-member-functions). De methodes in mijn voorbeelden retourneren in zowel Java als C++ gewoon referenties naar de juiste objecten.
Ehmm, dat bedoelde ik niet, maar ik zie dat je het zo kan lezen. Die opmerking over soorten pointers was in versie die ik gepost heb overbodig
Wie trösten wir uns, die Mörder aller Mörder?
bloedje efficient en Java gaan sowieso niet samen. Als je game van een dergelijk caliber is dat dit uit gaat maken en je bent in Java bezig dan heb je de verkeerde keuze gemaakt.JKVA schreef op donderdag 06 juli 2006 @ 07:31:
@oisyn: Ik ben benieuwd in hoeverre een Singleton in Java "bloedje efficient" is
Lees mijn post nog eens door, want volgens mij snap je niet helemaal wat ik gezegd hebaangezien het gewoon een andere klasse is
't Wordt trouwens tijd dat Parasietje eens een reactie post.
[ Voor 32% gewijzigd door .oisyn op 06-07-2006 12:09 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Ik merk idd dat ik "iets" gemist heb..oisyn schreef op donderdag 06 juli 2006 @ 12:01:
[...]
bloedje efficient en Java gaan sowieso niet samen. Als je game van een dergelijk caliber is dat dit uit gaat maken en je bent in Java bezig dan heb je de verkeerde keuze gemaakt.
[...]
Lees mijn post nog eens door, want volgens mij snap je niet helemaal wat ik gezegd heb
't Wordt trouwens tijd dat Parasietje eens een reactie post.
Fat Pizza's pizza, they are big and they are cheezy
Verwijderd
Het hangt er natuurlijk een klein beetje vanaf hoe je je singleton precies opzet. Dikwijls worden singletons via een factory pattern verkregen. Dat implementeer je typisch door een object van alleen non-public ctor's te voorzien en een public method getInstance() die een object van z'n eigen type terug geeft. Dit object is voor de gebruikers ervan een gewoon object en alle calls erop zijn in Java gewoon virtual. Er zit geen speciale performance winst in deze variant (tenzij je anders 1000'den keren een instantie van dit object had moeten aanmaken, maar dit is niet echt typisch om te doen)..oisyn schreef op donderdag 06 juli 2006 @ 02:29:
[...]
Hier wil ik dan wel weer even op inspringen door te zeggen dat het misschien niet altijd even netjes is maar wel bloedje efficient is. Globale variabelen (wat singletons effectief zijn als je de resulterende assembly code bekijkt) kosten vrij weinig en zijn snel te accessen.
De andere variant is om in Java static methods te gebruiken. Static methods zijn nooit virtual en er staat ook een aparte opcode voor (invokestatic vs invokevirtual). Dit zou in Java theoretisch een performance winst kunnen opleveren, maar vanwege de run-time optimalisaties die de VM doet kun je op voorhand niet zeggen naar welke cpu assembly deze twee high-level opcodes uiteindelijk gaan worden omgezet (hangt mede van het feit af of de code in kwestie een hotspot wordt tijdens run-time).
Ik kan me wel goed voorstellen dat voor commerciele games het in C++ inderdaad de moeite waard is om singletons op de manier te gebruiken zoals .oisyn verteld.
In business software speelt dit echter een stuk minder. Bekende situaties waar een singleton wel bewezen op z'n plaats is, is bijvoorbeeld als er sprake is van een job scheduler. Hier gebruik je geen singleton omdat je dan zo makkelijk erbij kunt en absoluut niet omdat dan de method calls op de scheduler een nanoseconde minder duren, maar simpelweg vanwege het feit dat er logisch maar 1 scheduler mag bestaan (zie bv Quartz). Een ander bekend voorbeeld vanwege dezelfde reden is een driver voor iets.
Een soort variant op de singleton die je ook nog wel eens ziet is een soort semi-singleton. In dit geval is er niet 1 globaal 'ding', maar is er 1 instantie per thread. Deze maken dan gebruik van een factory icm TLS ipv statics. Dit kan handig zijn bij frameworks en event-handling. Het framework zet dan een context object in TLS en roept de event handler code aan. Deze heeft dan ook vele methods diep nog makkelijk toegang tot de 'context'. In Java EE is de JSF context daar een voorbeeld van. Het alternatief is overal dit context object doorgeven. Omdat de handler code (verwar niet met de business logic die deze weer oproept) toch al framework specific is, is een well known dependency hier niet (zo) erg.
In vele andere gevallen zijn singletons in business software niet zo wenselijk.
Een bekend 'fout' voorbeeld is bv business logic die een DB connectie uit een singleton haalt met static methods. Dit gaat namelijk fout bij unit testen en gaat ook fout als je die code in een ander project wil gebruiken waar de DB connectie op hele andere wijze verkregen wordt. Het punt hier is dat object een black-box is met harde dependencies ergens heen. Als er een static call ergens midden in een functie staat, kun jij extern dat object niet bewegen om z'n connectie ergens anders vandaan te halen.
Een ander zo'n bekend voorbeeld is een singleton (static) settings object hebben. Dit zie je ook hele volkstammen van programmeurs doen. Er is binnen 1 project wel sprake dat er logisch maar 1 settings object is, maar de fout zit hem er hierin dat vele programmeurs dit object dan gebruiken om zelf hun object intern te configgen. Binnen dat ene project werkt dit wel, maar ook hier gaat dit dan fout zodra je deze code wilt unit testen of in een ander project wilt gebruiken wat zijn settings op een hele andere manier afhandeld.
Behalve unit-testen en re-use hebben singletons nog het nadeel dat het snel code op kan leveren die niet thread-safe is. In multi-threaded omgevingen (is Java EE eigenlijk automatisch) moet je dus extra goed opletten dat alles bewaakt wordt met iets dat mutual exclusion garandeerd voor alles dat een veranderbare state heeft.
Dat hangt er natuurlijk vanaf of al die referenties 'toevallig' naar 1 en hetzelfde systeem wijzen. Als dat zo is zal het niet meer memory kosten, maar heb je nog wel de flexibiliteit om waar nodig een object een andere referentie te laten gebruiken. Je hebt dan practisch voor elk systeem nog steeds maar 1 object zonder dat je de gebruikende objecten afdwingt 1 specificieke class te gebruiken.Als elk object in je game referenties moet gaan houden naar verschillende systemen (Game, RenderDevice, ResourceLoader, WeetIkNietWat) kost dat meer mem, wat op z'n beurt ook weer meer cache-misses en dus tragere code oplevert.
Ik snap wat je bedoeld. Aan de andere kant wordt het voorbeeld wat jij noemt vaak juist een dependency genoemt. Character is in jouw geval tightly coupled aan een specificieke renderer. Het zal concreet niet spelen, maar wat als jij nu als gebruiker van character een andere renderer wil gebruiken?Het werkt ook goed tegen onnodige dependencies. Iemand die een character instantieert is niet geïnteresseerd in de renderer, terwijl dat object zichzelf wel moet kunnen tekenen.
JKVA schreef op donderdag 06 juli 2006 @ 18:46:
Ik merk idd dat ik "iets" gemist heb.Maar goed, ik programmeer dan ook J2EE, en dan denk je niet aan al die low-level zaken. (we kopen gewoon nieuwe hardware, maar dat is in jullie geval natuurlijk niet acceptabel
)
Dat is niet altijd een bruikbare aanpak. Een collega van me heeft laatst bij een hard groeiend bedrijf een stukje inefficientie uit de code gehaald, zodat ze geen nieuwe server hoefden te kopen. Bovendien zou 1 server nu betekenen dat ze over 6 maanden nog 2 servers nodig hadden en over 12 nog 4. Als je meest kostbare (in processortijd) deel exponentieel schaalt, dan helpt het kopen van nieuwe server niets.
Wie trösten wir uns, die Mörder aller Mörder?
@hierboven verder: Het is toch zo dat als B van A afhankelijk is, en C van B, dat C dan ook van A afhankelijk is?
Ik gebruik nu bijna nooit meer een Singleton. Ik maak daarvoor altijd een interface en een plekje in een registry. Zo kan ik van te voren die registry een factory geven, of een direct object, welke ik dan met andere objecten weer ophaal. Werkt in princiepe hetzelfde, als je classes de concrete class niet direct kennen. Het dwingt natuurlijk niet af dat er maar 1 instantie is, maar het geeft je wel de meeste (meer) flexibiliteit.
Ik zeg ook niet dat efficientie me niets interesseert, integendeel zelfs, maar naar mijn idee zit de echte performancewinst ergens anders dan in die paar extra parameters/properties die je met een Singleton niet nodig hebt. Bijvoorbeeld in de gebruikte algoritmes en de database, maar dat laatste speelt in het geval van een spel niet.Confusion schreef op vrijdag 07 juli 2006 @ 07:40:
[...]
offtopic:
Dat is niet altijd een bruikbare aanpak. Een collega van me heeft laatst bij een hard groeiend bedrijf een stukje inefficientie uit de code gehaald, zodat ze geen nieuwe server hoefden te kopen. Bovendien zou 1 server nu betekenen dat ze over 6 maanden nog 2 servers nodig hadden en over 12 nog 4. Als je meest kostbare (in processortijd) deel exponentieel schaalt, dan helpt het kopen van nieuwe server niets.
Fat Pizza's pizza, they are big and they are cheezy
Doe eens even een simpel voorbeeldje, want ik volg je even niet meer.Michali schreef op vrijdag 07 juli 2006 @ 08:05:
Ik gebruik nu bijna nooit meer een Singleton. Ik maak daarvoor altijd een interface en een plekje in een registry. Zo kan ik van te voren die registry een factory geven, of een direct object, welke ik dan met andere objecten weer ophaal. Werkt in princiepe hetzelfde, als je classes de concrete class niet direct kennen. Het dwingt natuurlijk niet af dat er maar 1 instantie is, maar het geeft je wel de meeste (meer) flexibiliteit.
https://fgheysels.github.io/
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
| // Domain public interface CustomerRepository { public Customer getByID(int customerID); // etc... } public class Registry { private static CustomerRepository customerRepository; public static void setCustomerRepository(CustomerRepository customerRepository) { this.customerRepository = customerRepository; } public static CustomerRepository getCustomerRepository() { return customerRepository; } } public class EenAnderDomeinObject { public void doeIets() { Customer customer = Registry.getCustomerRepository().getByID(12); // handelingen... } } // DataAccess public class DBCustomerRepository implements CustomerRepository { // methods... } // Main public class Main { public static void main(String[] args) { Registry.setCustomerRepository(new DBCustomerRepository()); } } |
Zo kun je dat in princiepe bij iedere Singleton doen, dat je hem ophaalt via een Registry (of iets dergelijks). Meestal vul ik de registry niet zo direct, maar voer ik hem een (of meer) Factory aan de hand van een configuratie waarde.
Ik had het over code dependencies.Michali schreef op vrijdag 07 juli 2006 @ 08:05:
@hierboven verder: Het is toch zo dat als B van A afhankelijk is, en C van B, dat C dan ook van A afhankelijk is?
Als A een B moet constructen, en B heeft daarbij een C nodig die A moet aanleveren, dan moet A die dus ook ergens vandaan halen zonder dat hij geinteresseerd is in C. Als B zijn C zelf ergens vandaan kan halen dan heeft A dus geen code dependency meer op C.
[ Voor 81% gewijzigd door .oisyn op 07-07-2006 12:23 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Dat dacht ik idd ook..oisyn schreef op vrijdag 07 juli 2006 @ 12:20:
En hoe is dat anders dan een singleton? In feite is je Registry ook een singleton.
https://fgheysels.github.io/
Als ik nu een class heb, SingletonClass bijvoorbeeld, dan geef ik die geen functie getInstance(), maar dan geef ik de registry daar de controle over, middels een method getSingletonClass die een object terug geeft die de interface van SingletonClass implementeerd. Dat was wat ik bedoelde.
Wat is het verschil dan met een Singleton 'settings' object bv, die een Repository kan aanleveren ?Michali schreef op vrijdag 07 juli 2006 @ 13:40:
Registry is wel een Singleton ja. Maar DBCustomerRepository niet, hoewel je die wel als singleton wil gebruiken. Het ging dus niet over de registry, maar over de repository.
1
| ICustomerRepository rep = Settings.CreateCustomerRepository(); |
Waarbij de Settings class verantwoordelijk is om de juiste implementatie van de CustomerRepository te instantieren.
https://fgheysels.github.io/
Ik noem het dan een Factory, (eigenlijk is het een Abstract Factory), en die voer ik aan de Registry. Als er dan een Repository aan de Registry gevraagd wordt, gebruikt deze de Factory om er een te maken als die nog niet bestaat.
Verwijderd
In C++ is het voorkomen van een type in de interface van een ander type mischien wat vervelenderer (zeker als dat vaker voorkomt) omdat je dan inderdaad include dependencies hebt geintroduceerd t.o.v. de situatie dat het gebruikte type compleet een private detail is in C..oisyn schreef op vrijdag 07 juli 2006 @ 12:20:
En hoe is dat anders dan een singleton? In feite is je Registry ook een singleton.
Ik had het over code dependencies.
Als A een B moet constructen, en B heeft daarbij een C nodig die A moet aanleveren, dan moet A die dus ook ergens vandaan halen zonder dat hij geinteresseerd is in C. Als B zijn C zelf ergens vandaan kan halen dan heeft A dus geen code dependency meer op C.
In Java speelt dat absoluut niet door de manier waarop de class hierarchy 'automatisch' ingedeeld wordt (dit is 1 van de weinige aspecten waarin Java -echt- beter is dan C++).
Vervolgens, als je de C een interface laat zijn die je met je B meelevert, dan is er ook geen dependency op een bepaalde class (en alle code die die class weer nodig heeft). Dit geldt dan zowel compile-time als run-time.
Tevens wil ik dit stukje er nog even apart uitlichten:
Het is bij deze wijze van ontwerpen niet perse noodzakelijk dat A de C die B nodig heeft MOET aanleveren. Het is heel goed mogelijk dat B een alternatieve ctor heeft en bij gebruik van de default ctor zelf voor een redelijke default zorgt. Waar het omgaat is dat jij als gebruiker de controlle kunt houden op wat je classen doen. Opzich staat het ontwerpen van code op deze manier los van Singletons zelf. Immers, je kunt net zogoed een dependency hebben in je code als je ergens midden in een functie gewoon een nieuw object van een bepaald type alloceerd dat geen singleton is. Het inversion of control (IoC) principe beargumenteerd juist dat je dit niet moet doen (in bepaalde gevallen).en B heeft daarbij een C nodig die A moet aanleveren
Als je echter singletons op de statische manier gebruikt, dan is het niet meer mogelijk om je code alternatief een andere implementatie te laten gebruiken.
Bv
1
2
3
4
5
6
7
8
| public class Foo { void bar() { // ... Singleton.doSomething(); // static reference; cannot be replaced } } |
Vergelijk dit met:
1
2
3
4
5
6
7
8
9
10
11
12
13
| public class Foo { MyInterFace kaz = Singleton.getInstance(); // singleton, but referenced through an object void bar() { kaz.doSomething(); } // optionally, give the user the ability to set the class bar uses void setKaz(MyInterface kaz) { this.kaz = kaz; } } |
Niet dat bovenstaande code nu de absoluut beste manier is, maar ik hoop dat dit wel duidelijk het principe aangeeft dat het static aanroepen van singletons het toepassen van IoC onmogelijk maakt.
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Iemand zou het boek design patterns eens moeten lezenVerwijderd schreef op woensdag 05 juli 2006 @ 16:44:
Als je niet overal referenties naar die singletons wilt opnemen
Standaard Java singleton implementatie:
1
2
3
4
5
6
7
8
9
10
11
12
13
| public class Singleton
{
private Singleton() {}
public static Singleton getSingleton()
{
if(singleton = null)
singleton = new Singleton();
return singleton;
}
private static Singleton singleton = null;
} |
Zie niet wat de problemen met 'pointers' nou moeten zijn.
Het is per definitie niet de bedoeling statische methoden anders dan de 'getInstance' methode te gebruiken, da's het hele punt achter die design pattern.Verwijderd schreef op vrijdag 07 juli 2006 @ 22:52:
Als je echter singletons op de statische manier gebruikt, dan is het niet meer mogelijk om je code alternatief een andere implementatie te laten gebruiken.
[ Voor 29% gewijzigd door Hydra op 13-07-2006 14:26 ]
https://niels.nu
Je kunt als je wilt een interface gebruiken en dan aan de hand van bijvoorbeeld een parameter een andere implementatie returnen.Verwijderd schreef op vrijdag 07 juli 2006 @ 22:52:
[...]
Als je echter singletons op de statische manier gebruikt, dan is het niet meer mogelijk om je code alternatief een andere implementatie te laten gebruiken.
[...]
Dan krijg je een soort geparametriseerde Singleton.
Fat Pizza's pizza, they are big and they are cheezy
WAT een stommiteit... Ik dacht dat Java met de volgende code twee aparte objecten maakt:
1
2
3
4
| Integer x; Integer y; x = new Integer(25); y = x; |
Ik dacht dat bij x.setValue(40) (nee, deze methode bestaat niet, maar denk even mee), y nog steeds de waarde 25 had. Dit is blijkbaar niet zo...
Wat een reeks reacties voor zoiets simpels. Ik schaam me diep.
WebDAV in Vista is horribly broken. Ik wil het fixen, maar ben nog steeds op zoek naar de tarball met de source...
Verwijderd
Parasietje schreef op zaterdag 22 juli 2006 @ 16:03:
Even een hele late reactie:
WAT een stommiteit... Ik dacht dat Java met de volgende code twee aparte objecten maakt:
code:
1 2 3 4 Integer x; Integer y; x = new Integer(25); y = x;
Ik dacht dat bij x.setValue(40) (nee, deze methode bestaat niet, maar denk even mee), y nog steeds de waarde 25 had. Dit is blijkbaar niet zo...
Wat een reeks reacties voor zoiets simpels. Ik schaam me diep.
En terechtParasietje schreef op zaterdag 22 juli 2006 @ 16:03:
Ik schaam me diep.
OO zonder het concept van pointers/references is een beetje zinloos imho.
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
In dit eenvoudige voorbeeld is het idd nogal makkelijk te zien, maar in wat complexere code kun je toch gemakkelijk zo'n fout maken, gewoon omdat je eventjes iets vergeet te clonen..oisyn schreef op zondag 23 juli 2006 @ 10:03:
[...]
En terecht
OO zonder het concept van pointers/references is een beetje zinloos imho.
Dus, ik weet niet wat de context was, maar zo stom hoeft het nog niet eens te zijn. (in het voorbeeld dat je zelf aangaf is het natuurlijk wel vrij schandalig
Fat Pizza's pizza, they are big and they are cheezy
Verwijderd
In Java wel, maar volgens mij in C# kan je dit niet zien. Je type kan namelijk een struct zijn. Anders dan in C++ (waar een class en een struct identiek zijn en alleen de default access verschilt), heeft in C# een struct value semantics. Er wordt in bovenstaand voorbeeld dan wel degelijk een copy gemaakt. Je ziet dat niet aan de code, maar moet de definitie van je type opzoeken (of zien met behulp van je IDE).JKVA schreef op zondag 23 juli 2006 @ 11:05:
[...]
In dit eenvoudige voorbeeld is het idd nogal makkelijk te zien, maar in wat complexere code kun je toch gemakkelijk zo'n fout maken, gewoon omdat je eventjes iets vergeet te clonen.