[OOP] Singleton-structuur vermijden

Pagina: 1
Acties:
  • 253 views sinds 30-01-2008
  • Reageer

Acties:
  • 0 Henk 'm!

  • Parasietje
  • Registratie: Juli 2004
  • Laatst online: 10-06-2024
Ik heb het volgende probleem:

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).

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?

WebDAV in Vista is horribly broken. Ik wil het fixen, maar ben nog steeds op zoek naar de tarball met de source...


Acties:
  • 0 Henk 'm!

  • mOrPhie
  • Registratie: September 2000
  • Laatst online: 08-07 23:56

mOrPhie

❤️❤️❤️❤️🤍

Parasietje schreef op dinsdag 04 juli 2006 @ 14:40:
Ik ben C++ aan het overwegen om deze nare chaos op te lossen
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.

Een experimentele community-site: https://technobabblenerdtalk.nl/. DM voor invite code.


Acties:
  • 0 Henk 'm!

  • Y0ur1
  • Registratie: Oktober 2000
  • Niet online
Die hele omweg is mijns inziens gewoon een ontwerp kwestie, wat dat te maken heeft met pointers/of het ontbreken daarvan(java heeft btw wel pointers alleen niet expliciet zoals in c of c++) snap ik niet echt.

[ Voor 3% gewijzigd door Y0ur1 op 04-07-2006 14:56 ]


Acties:
  • 0 Henk 'm!

  • ReverendBizarre
  • Registratie: December 2001
  • Laatst online: 24-03-2021
Zou je misschien uit kunnen leggen waarom je denkt pointers nodig te hebben om dit op te lossen en waarom dat niet in Java kan (met references)? Ik begrijp volgens mij niet precies wat het probleem is waar je mee zit.

Acties:
  • 0 Henk 'm!

  • Not Pingu
  • Registratie: November 2001
  • Laatst online: 16-06 15:45

Not Pingu

Dumbass ex machina

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?
Wat zou het nadeel van een Singleton pattern zijn dan? Je hebt als het goed is maar 1 Game object.

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.


Acties:
  • 0 Henk 'm!

  • CaptBiele
  • Registratie: Juni 2002
  • Laatst online: 27-08-2021

CaptBiele

No Worries!

Het zal inderdaad wel overzichtelijker zijn met een goede Singleton. Ik denk ook dat het meer een ontwerp kwestie is.

ik ben nou juist blij om van die pointers af te zijn.... (prog in C#)

Acties:
  • 0 Henk 'm!

  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

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.

Fat Pizza's pizza, they are big and they are cheezy


Acties:
  • 0 Henk 'm!

  • Alex
  • Registratie: Juli 2001
  • Laatst online: 23-06 21:54
Ja, je kunt singletons gebruiken als een garbage-object, echter, je kunt er ook voor kiezen om dat niet te doen en je strict te houdne bij je design. Als ze daadwerkelijk ranzig zijn in je ogen, dan kun je beter overstappen naar C++, want een taal als Java maakt ook gebruik van Context object(in, out), die je vrijwel identiek benadert, maar zonder 'getInstance'.
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


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:45

.oisyn

Moderator Devschuur®

Demotivational Speaker

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.
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.

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.


Acties:
  • 0 Henk 'm!

  • Not Pingu
  • Registratie: November 2001
  • Laatst online: 16-06 15:45

Not Pingu

Dumbass ex machina

Een static object is inderdaad nogal wat anders dan een globale variabele, zeker wat groepering van functionaliteit betreft.

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.


Acties:
  • 0 Henk 'm!

  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

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).
Main.getGame().getPlayer(0).getPawns() is volgens jou een grotere omweg dan *Main->*Game->Player[0]*->*Pawns (of iets dergelijks, ik spreek geen C++)?

[ Voor 3% gewijzigd door Confusion op 05-07-2006 07:32 ]

Wie trösten wir uns, die Mörder aller Mörder?


Acties:
  • 0 Henk 'm!

  • Boss
  • Registratie: September 1999
  • Laatst online: 15:22

Boss

+1 Overgewaardeerd

Je kan het natuurlijk altijd nog in Delphi gaan maken, of de opensource variant daarvan: Freepascal. Is inmiddels ook erg cross-platform. In ieder geval linux/macos/windows/gameboy en nog een hele meuk.

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.


Acties:
  • 0 Henk 'm!

  • BCC
  • Registratie: Juli 2000
  • Laatst online: 19:48

BCC

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++)?
Volgens mij slaat de compiler beide versies plat naar een platte pointer.

Na betaling van een licentievergoeding van €1.000 verkrijgen bedrijven het recht om deze post te gebruiken voor het trainen van artificiële intelligentiesystemen.


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:45

.oisyn

Moderator Devschuur®

Demotivational Speaker

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++)?
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...

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.


Acties:
  • 0 Henk 'm!

  • ReverendBizarre
  • Registratie: December 2001
  • Laatst online: 24-03-2021
Dat is ook wat ik niet helemaal begrijp aan dit topic. References in Java verschillen in gebruik niet zo erg veel van C++ pointers dus ik begrijp nog altijd niet helemaal wat de TS nou denkt op te lossen door te kiezen voor C++ ipv Java. Je kan references in Java gewoon assignen en re-assignen, op NULL zetten, etc. (in tegenstelling tot references in C++ die je niet mag re-assignen en ook niet NULL kan maken) net als pointers in C++. Eigenlijk het enige wat je niet met Java references en wel met pointers kan doen is pointer arithmetic.

Acties:
  • 0 Henk 'm!

  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

.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...
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.

Wie trösten wir uns, die Mörder aller Mörder?


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:45

.oisyn

Moderator Devschuur®

Demotivational Speaker

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 :)

Java:
1
2
Main.getGame().getPlayer(0).getPawns()
Main.game.players[0].pawns

C++:
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.


Acties:
  • 0 Henk 'm!

  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

.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 :)
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.

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?


Acties:
  • 0 Henk 'm!

Anoniem: 99283

Als je niet overal referenties naar die singletons wilt opnemen laat je alle afhankelijkheden toch gewoon run-time injecteren (Dependency Injection) met bijv. het Spring framework et voila: loose coupling (als je dat bedoelt iig; anders snap ik je probleem met singletons niet :P).

[ Voor 27% gewijzigd door Anoniem: 99283 op 05-07-2006 16:46 ]


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:45

.oisyn

Moderator Devschuur®

Demotivational Speaker

Confusion 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.
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.

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.


Acties:
  • 0 Henk 'm!

  • ReverendBizarre
  • Registratie: December 2001
  • Laatst online: 24-03-2021
.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?
Ik vermoed inderdaad dat daar het probleem zit.

Acties:
  • 0 Henk 'm!

Anoniem: 42145

IrishMaiden schreef op woensdag 05 juli 2006 @ 17:04:
[...]


Ik vermoed inderdaad dat daar het probleem zit.
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:

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.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:45

.oisyn

Moderator Devschuur®

Demotivational Speaker

Anoniem: 42145 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.
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.

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.


Acties:
  • 0 Henk 'm!

  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

@oisyn: Ik ben benieuwd in hoeverre een Singleton in Java "bloedje efficient" is, aangezien het gewoon een andere klasse is. Het renderen van een Karakter in een spel kun je ook met een Renderobject doen dat pas in de methode als parameter meegegeven wordt. (Scheelt een hele waslijst aan parameters in je constructor)

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


Acties:
  • 0 Henk 'm!

  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

.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.
offtopic:
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 :o.

Wie trösten wir uns, die Mörder aller Mörder?


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:45

.oisyn

Moderator Devschuur®

Demotivational Speaker

JKVA schreef op donderdag 06 juli 2006 @ 07:31:
@oisyn: Ik ben benieuwd in hoeverre een Singleton in Java "bloedje efficient" is
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.
aangezien het gewoon een andere klasse is
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.

[ 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.


Acties:
  • 0 Henk 'm!

  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

.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.
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 :))

Fat Pizza's pizza, they are big and they are cheezy


Acties:
  • 0 Henk 'm!

Anoniem: 42145

.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.
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).

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.
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.
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.
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.
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?

Acties:
  • 0 Henk 'm!

  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

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 :))
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.

Wie trösten wir uns, die Mörder aller Mörder?


Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Dat is zeker zo, maar je moet niet proberen alles er uit te persen door te optimaliseren. Dan is het na een tijdje gewoon goedkoper om nieuwe hardware aan te schaffen, en dat is toch wel de bepalende factor lijkt me.


@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.

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

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.
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.

Fat Pizza's pizza, they are big and they are cheezy


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:36
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.
Doe eens even een simpel voorbeeldje, want ik volg je even niet meer.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Een goed voorbeeld is een repository. Daar wil je er maar 1 van hebben, maar je wilt niet van een concrete class afhankelijk zijn. Dan defineer je een interface, en stop je een method in je registry waarmee je de repository kunt ophalen.
Java:
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.

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:45

.oisyn

Moderator Devschuur®

Demotivational Speaker

En hoe is dat anders dan een singleton? In feite is je Registry ook een singleton.
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?
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.

[ 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.


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:36
.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.
Dat dacht ik idd ook.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
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.

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.

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:36
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.
Wat is het verschil dan met een Singleton 'settings' object bv, die een Repository kan aanleveren ?
code:
1
ICustomerRepository rep = Settings.CreateCustomerRepository();

Waarbij de Settings class verantwoordelijk is om de juiste implementatie van de CustomerRepository te instantieren.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Zo doe ik dat ook :P

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.

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

Anoniem: 42145

.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 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.

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:
en B heeft daarbij een C nodig die A moet aanleveren
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).

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

Java:
1
2
3
4
5
6
7
8
public class Foo {

   void bar() {
      // ...
      Singleton.doSomething(); // static reference; cannot be replaced
   }

}


Vergelijk dit met:

Java:
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.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:45

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ik snap het verband met de statische functions niet, ik heb daar iig nog geen woord over gerept :). Ik prefereer in zo'n geval ook de getInstance die een interface returnt. De efficientie waar ik het in het begin over had was dat het geheugengebruik nogal explodeert als je voor elk wissewasje een hele waslijst aan verschillende interfaces bij moet houden (zeg maar de kandidaten voor de singletons), wat je cache absoluut niet ten goede komt. Dat dat in Java sowieso niet speelt is vrij duidelijk, het zijn minor optimalisaties waar je je niet echt mee bezig moet houden als het geheel toch al in een VM draait, dat meestal nog veel meer aan boekhouding doet.

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.


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 10-07 13:07
Anoniem: 99283 schreef op woensdag 05 juli 2006 @ 16:44:
Als je niet overal referenties naar die singletons wilt opnemen
Iemand zou het boek design patterns eens moeten lezen ;)

Standaard Java singleton implementatie:

code:
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.
Anoniem: 42145 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.
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.

[ Voor 29% gewijzigd door Hydra op 13-07-2006 14:26 ]

https://niels.nu


Acties:
  • 0 Henk 'm!

  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Anoniem: 42145 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.
[...]
Je kunt als je wilt een interface gebruiken en dan aan de hand van bijvoorbeeld een parameter een andere implementatie returnen.

Dan krijg je een soort geparametriseerde Singleton.

Fat Pizza's pizza, they are big and they are cheezy


Acties:
  • 0 Henk 'm!

  • Parasietje
  • Registratie: Juli 2004
  • Laatst online: 10-06-2024
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.

WebDAV in Vista is horribly broken. Ik wil het fixen, maar ben nog steeds op zoek naar de tarball met de source...


Acties:
  • 0 Henk 'm!

Anoniem: 99283

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.
:+

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:45

.oisyn

Moderator Devschuur®

Demotivational Speaker

En terecht :+

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.


Acties:
  • 0 Henk 'm!

  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

.oisyn schreef op zondag 23 juli 2006 @ 10:03:
[...]

En terecht :+

OO zonder het concept van pointers/references is een beetje zinloos imho.
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.

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 :P)

Fat Pizza's pizza, they are big and they are cheezy


Acties:
  • 0 Henk 'm!

Anoniem: 42145

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.
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).
Pagina: 1