There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.
Je eigen tweaker.me redirect
Over mij
meubel.GetType().ToString() == "string" is natuurlijk veel mooier dan meubel instanceof string, duh!
'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.
To approve, or not to approve, that is the question..
Anyone who gets in between me and my morning coffee should be insecure.
To approve or not to approve == true, dûh. Zijn we hier nu programmeurs of niet?
Soultaker schreef op woensdag 06 april 2011 @ 15:28:
offtopic:
To approve or not to approve == true, dûh. Zijn we hier nu programmeurs of niet?
En hoe weet jij zo zeker dat het niet FileNotFound is?
Wishlist Backpack Survivors op Steam !
Het drawable voorbeeld vond ik mooi (omdat het praktisch is). Daarbij heet de interface namelijk een collectie aan drawables, de gamecontroller een collectie van gameentities en de ai een collectie van monsters.
De interface, gamecontroller en de ai hoeven deze types niet meer te checken. Ze accepteren namelijk geen instances van andere typen.
Wanneer is de "Kast.open" en "Stoel.zit" realistisch? Als je een grote schuur hebt met honderden meubels en je gaat kijken of ze allemaal nog werken. Dan is het best logisch dat als je voor een meubel staat, dat je even controleert watvoor meubel het is en afhankelijk daarvan even kijkt of het er goed uit ziet.
Dan weet je gelijk waarom je Openable en Sitable moet implementeren. Anders moet je voor "Stoel" en "Bank" opnieuw de testmethod aanmaken.
Bovenstaand lijkt me in de programmeer wereld niet vaak voorkomen, behalve als je dus voorbeeld code aan het schrijven bent.
(to apporove or not to approve) instanceof FileNotExist == falseofftopic:
En hoe weet jij zo zeker dat het niet FileNotExists is?
controleerWerking() zou dan best wel weer een methode kunnen zijn op Meubel, die afhankelijk van de meubel verschillend geïmplementeerd is.ReenL schreef op woensdag 06 april 2011 @ 15:32:
Wanneer is de "Kast.open" en "Stoel.zit" realistisch? Als je een grote schuur hebt met honderden meubels en je gaat kijken of ze allemaal nog werken. Dan is het best logisch dat als je voor een meubel staat, dat je even controleert watvoor meubel het is en afhankelijk daarvan even kijkt of het er goed uit ziet.
Hoeft niet per se. Kijk bijvoorbeeld eens naar Java3D, daar wordt alles gewoon in een grote boomstructuur gemikt.ReenL schreef op woensdag 06 april 2011 @ 15:32:
Het drawable voorbeeld vond ik mooi (omdat het praktisch is). Daarbij heet de interface namelijk een collectie aan drawables, de gamecontroller een collectie van gameentities en de ai een collectie van monsters.
Niet dat ik dat nou echt een fantastische API vind overigens, maar het is niet zonder meer zo dat je collecties altijd volledig uitgespecificeerd zijn.
[ Voor 34% gewijzigd door .oisyn op 06-04-2011 15:41 ]
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.
Verwijderd
Vanuit performance-perspectief zal dat ongetwijfeld een goed idee zijnReenL schreef op woensdag 06 april 2011 @ 15:32:
Wel geweldig dat we allemaal een hele theoretische case aan het oplossen zijn.
Het drawable voorbeeld vond ik mooi (omdat het praktisch is). Daarbij heet de interface namelijk een collectie aan drawables, de gamecontroller een collectie van gameentities en de ai een collectie van monsters.
Maar hoe krijg je een object in de juiste collecties?De interface, gamecontroller en de ai hoeven deze types niet meer te checken. Ze accepteren namelijk geen instances van andere typen.
Verwijderd
Dat is de reden waarom mensen die roepen dat je geen goto mag gebruiken en dat eval altijd vies is, niet al te serieus genomen moeten worden.Vinnienerd schreef op woensdag 06 april 2011 @ 16:46:
Mensen die gaan roepen dat instanceof ranzig is zijn bezig met "overcorrect programmeren". Abstract denken is mooi, maar soms moet je gewoon specifiek zijn
Ik denk dat de consensus is dat onervaren programmeurs er geen gebruik van zouden moeten maken, maar dat het gebruik in sommige gevallen wel is te verantwoorden. Om te bepalen of dat zo is, moet je uiteraard het nodige inzicht en de nodige ervaring hebben.
Maar dan nog vind ik instanceof van compleet ander kaliber dan goto en eval.
[ Voor 6% gewijzigd door Verwijderd op 06-04-2011 16:57 ]
Er zijn allerlei code constructs die je bij voorkeur niet zou moeten gebruiken. Maar soms wordt je inderdaad voor de keuze gesteld om toch maar de construct te gebruiken of er omheen te werken.Verwijderd schreef op woensdag 06 april 2011 @ 16:56:
Maar dan nog vind ik instanceof van compleet ander kaliber dan goto en eval.
Als je met nette en duidelijke code kunt vermijden dat je de constructs gebruikt of de reden dat je het uberhaupt checkt kunt voorkomen... graag. Maar als je om een enorme (maar wel nette) hoeveelheid code moet produceren enkel om hetzelfde probleem op te lossen? Sja, dan moet je je alsnog weer achter je oren gaan krabben. Misschien was de instanceof (of goto, eval, meerdere returns, etc) dan toch een beter idee.
Dit is een gevaarlijke vraagHydra schreef op woensdag 06 april 2011 @ 13:10:
Als je "sit()" in "Meubel" stopt moet je collection net zo goed een "CannnotSitException" af gaan vangen omdat je het aanroept op een meubel (kast) waarop je niet kunt zitten toch? Wat is volgens jou efficienter; vooraf kijken of een object wel een interface implementeert, of gewoon maar aanroepen die hap en kijken wat er gebeurt?
Desalniettemin zou ik in dit geval ook de instanceof-variant kiezen en hooguit bij wijze van micro-optimalisatie vol in het kritieke pad onderaan de lijst overwegen om te kijken of er een alternatieve - nog efficientere - methode is om het te doen
Dat schrijf ik toch ook? Of heb je het nu niet tegen mij?Verwijderd schreef op woensdag 06 april 2011 @ 16:56:
[...]
Maar dan nog vind ik instanceof van compleet ander kaliber dan goto en eval.
I think we have a winner. Dat is wel de ultieme reden dat het gewoon helemaal compleet fout is..oisyn schreef op woensdag 06 april 2011 @ 15:04:
Ook leuk hoe die code niet werkt met subclasses van Kast.
class ServiesKast extends Kast. Dat IS gewoon een kast, maar volgens het voorbeeld niet. Te slecht gewoon.
Ik bedoel efficienter vanuit een programmeerstandpunt, niet performance. Dat zou wel een vorm van premature optimization zijnACM schreef op woensdag 06 april 2011 @ 17:26:
Dit is een gevaarlijke vraagAls geen (of slechts enkele) van de objecten een exception opgooien (dus alles Sitable is) is het namelijk goed mogelijk dat de variant met exception-check efficienter is dan de instanceof-variant.
https://niels.nu
Zoals .oisyn al zei: het probleem zit waarschijnlijk helemaal niet in Meubel/Kast/Openable, maar in de collectie/array van het type Meubel en het beoogde gebruik daarvan.
Het feit dat je instanceof nodig hebt om bepaalde instanties in die lijst eruit te filteren, is eerder een indicatie van een probleem met die lijst, dan van een probleem met de types van die instanties.
Als je graag alle Kasten wilt openen, moet je een collectie van Kasten maken, geen collectie van Meubels.
[ Voor 4% gewijzigd door Herko_ter_Horst op 06-04-2011 19:44 ]
"Any sufficiently advanced technology is indistinguishable from magic."
Verwijderd
Ik had het niet zozeer tegen jou, ik was aan het voortborduren op de gedachteVinnienerd schreef op woensdag 06 april 2011 @ 17:28:
Dat schrijf ik toch ook? Of heb je het nu niet tegen mij?
Maar bij het toevoegen weet je nou eenmaal niet altijd wat het is, en dus zul je op dat punt moeten controleren wat het is ( met instanceof bijvoorbeeld ). Als er een duidelijk onderscheid te maken is bij het toevoegen, moet je dat zeker doen. Maar vroeger of later kom je vanzelf een situatie tegen waar je eigenlijk een te generieke collectie gebruikt.Herko_ter_Horst schreef op woensdag 06 april 2011 @ 18:52:
Als je graag alle Kasten wilt openen, moet je een collectie van Kasten maken, geen collectie van Meubels.
“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”
De vraag is of in zo'n geval de verantwoordelijkheden goed liggen. Moet de class die de generieke collectie van Meubels beheert, wel dezelfde class zijn die Kasten open doet?Woy schreef op woensdag 06 april 2011 @ 19:44:
[...]
Maar bij het toevoegen weet je nou eenmaal niet altijd wat het is, en dus zul je op dat punt moeten controleren wat het is ( met instanceof bijvoorbeeld ). Als er een duidelijk onderscheid te maken is bij het toevoegen, moet je dat zeker doen. Maar vroeger of later kom je vanzelf een situatie tegen waar je eigenlijk een te generieke collectie gebruikt.
"Any sufficiently advanced technology is indistinguishable from magic."
Hoe zie je het dan voor je? Natuurlijk is een Kamer ( o.i.d. ) niet de aangewezen class om meubels te openen, maar als er bijvoorbeeld een Persoon is die dat zou doen, dan moet die alsnog uit de kamer alle IOpenable objecten verkrijgen, en dan heb je daar alsnog iets van instanceof voor gebruiken.Herko_ter_Horst schreef op woensdag 06 april 2011 @ 19:51:
[...]
De vraag is of in zo'n geval de verantwoordelijkheden goed liggen. Moet de class die de generieke collectie van Meubels beheert, wel dezelfde class zijn die Kasten open doet?
“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”
Bij mij op mijn werk gebruiken we het waterval model en is dit niet van toepassingen. Klassendiagrammen en ontwerpen worden van tevoren opgezet met UML, zodat namen vaststaan en nooit zullen veranderen. Het is een kleine opoffering die je moet maken als je echt om de performance van je applicatie geeft.whoami schreef op woensdag 06 april 2011 @ 14:58:
[...]
Ja, en dan gaan we even gaan refactoren en die class een andere naam geven, of we verhuizen ze naar een andere namespace .... En dan werkt het plots niet meer.
[...]
![]()
Een helper is in dit geval een soort controller die de applicatie helpt om te bepalen welke meubelen een kast zijn. Dit is een veelgebruikte best-practice om de applicatie-logica, het data model en de presentatie-laag van elkaar te scheiden.Iedere class die eindigt op Helper is een toppunt van slecht OO programmeren. Wat doet een helper?
Zoals ik al eerder vertelde hoeft de naam van een namespace of klasse niet te veranderen als je van tevoren een goed ontwerp maakt. Mijn methode is een goede manier om op een snelle en efficiente manier te controleren welke classes de methode open() hebben.Het is een ranzige workaround die nog steeds neerkomt op het controleren van het type. In plaats van netjes het resultaat van GetType te gebruiken en te kijken of de instantie een Kast is (*kuch* instanceOf) ga jij raar lopen doen met strings (wat als de namespace of erger nog de naam van de klasse verandert?).
Verder vind ik het beneden peil dat jullie mijn code op zo'n negatieve manier afkraken. Ik zit al 15 jaar in het vak en heb nog nooit negatieve feedback gehad op mijn code!
En je denkt serieus dat een string vergelijking beter performt dan een simpele type comparison?Big Joe schreef op woensdag 06 april 2011 @ 20:12:
[...]
Het is een kleine opoffering die je moet maken als je echt om de performance van je applicatie geeft.
Ten eerste is het zeker geen snelle efficiënte manier, en ten tweede is het ook erg lastig te onderhouden. Ook al maak je nog zo'n goed ontwerp van te voren, in de toekomst zullen er altijd wijzigingen of toevoegingen aan gedaan worden. Met deze manier van werken is het gewoon wachten totdat het mis gaat.Zoals ik al eerder vertelde hoeft de naam van een namespace of klasse niet te veranderen als je van tevoren een goed ontwerp maakt. Mijn methode is een goede manier om op een snelle en efficiente manier te controleren welke classes de methode open() hebben.
Het is niet bedoeld om je persoonlijk aan te vallen, maar de manier van werken die jij voorstelt is echt geen voorbeeld van hoe je zou moeten werken. Je hebt totaal geen enkele vorm van compile-time safety, refactoring tools werken er niet goed op ( Het scheelt dat Resharper bijvoorbeeld ook in stings zoekt, maar die heeft daarbij alsnog te weinig informatie om het altijd goed te doen.Verder vind ik het beneden peil dat jullie mijn code op zo'n negatieve manier afkraken. Ik zit al 15 jaar in het vak en heb nog nooit negatieve feedback gehad op mijn code!
“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”
Tenminste, dat hoop ik dan. Ik bedoel:
Dat kan je gewoon niet serieus menen als je "al 15 jaar in het vak zit".Klassendiagrammen en ontwerpen worden van tevoren opgezet met UML, zodat namen vaststaan en nooit zullen veranderen.
...
Zoals ik al eerder vertelde hoeft de naam van een namespace of klasse niet te veranderen als je van tevoren een goed ontwerp maakt.
Waterval en klassendiagrammen hebben nog minder dan niets met de performance van je applicatie te maken.Big Joe schreef op woensdag 06 april 2011 @ 20:12:
[...]
Bij mij op mijn werk gebruiken we het waterval model en is dit niet van toepassingen. Klassendiagrammen en ontwerpen worden van tevoren opgezet met UML, zodat namen vaststaan en nooit zullen veranderen. Het is een kleine opoffering die je moet maken als je echt om de performance van je applicatie geeft.
Het heeft toch te maken met de data?Een helper is in dit geval een soort controller die de applicatie helpt om te bepalen welke meubelen een kast zijn. Dit is een veelgebruikte best-practice om de applicatie-logica, het data model en de presentatie-laag van elkaar te scheiden.
Totdat er een nieuw meubelstuk wordt geïntroduceerd wat toevallig ook geopend moet kunnen worden. In het geval van de eerder genoemde code die gebruik maakt van een nette interface hoef je het nieuwe meubel alleen deze interface laten implementeren, en de rest van de code blijft onaangeraakt. In jouw geval moet je de naam van de klasse (die overigens door voortschrijdend inzicht wel degelijk kan veranderen) copypasten en in een string zetten.Zoals ik al eerder vertelde hoeft de naam van een namespace of klasse niet te veranderen als je van tevoren een goed ontwerp maakt. Mijn methode is een goede manier om op een snelle en efficiente manier te controleren welke classes de methode open() hebben.
Je lost er een niet-bestaand probleem (het om een of andere reden niet willen gebruiken van runtime typechecking) mee op.
Dan laat je je code aan de verkeerde mensen zien. Ik wil mezelf niet onervaren noemen, maar zelfs ik zie dat jouw ontwerp gewoon inherent slecht is. Wat overigens natuurlijk niets zegt over de code die je in je dagelijkse kostwinning produceert.Verder vind ik het beneden peil dat jullie mijn code op zo'n negatieve manier afkraken. Ik zit al 15 jaar in het vak en heb nog nooit negatieve feedback gehad op mijn code!
https://oneerlijkewoz.nl
Op papier is hij aan het tekenen, maar in de praktijk...
Joehoe, 1996 belde, ze willen hun wereldbeeld terug!Big Joe schreef op woensdag 06 april 2011 @ 20:12:
Bij mij op mijn werk gebruiken we het waterval model en is dit niet van toepassingen. Klassendiagrammen en ontwerpen worden van tevoren opgezet met UML, zodat namen vaststaan en nooit zullen veranderen. Het is een kleine opoffering die je moet maken als je echt om de performance van je applicatie geeft.
...
Een helper is in dit geval een soort controller die de applicatie helpt om te bepalen welke meubelen een kast zijn. Dit is een veelgebruikte best-practice om de applicatie-logica, het data model en de presentatie-laag van elkaar te scheiden.
...
Zoals ik al eerder vertelde hoeft de naam van een namespace of klasse niet te veranderen als je van tevoren een goed ontwerp maakt.
Oeh, ik bied me bij deze vrijwillig aan voor het doen van een code review!Verder vind ik het beneden peil dat jullie mijn code op zo'n negatieve manier afkraken. Ik zit al 15 jaar in het vak en heb nog nooit negatieve feedback gehad op mijn code!
Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'
Commentaar krijgen op je code kan vervelend zijn, maar je kunt er ook van leren. Ervaring zegt niet alles, zoals ik al eerder zei: je kunt ook ervaring hebben in het schrijven van slechte code. Nu kun je natuurlijk een prima programmeur zijn en zit je er in dit geval net naast, maar ik hoop dat je inziet waarom jouw voorgestelde oplossing hier niet klopt.
Dit kun je oplossen door de code aan te passen naar het volgende:Hydra schreef op woensdag 06 april 2011 @ 17:48:
[...]
I think we have a winner. Dat is wel de ultieme reden dat het gewoon helemaal compleet fout is.
class ServiesKast extends Kast. Dat IS gewoon een kast, maar volgens het voorbeeld niet. Te slecht gewoon.
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
| public class Meubel { public void plaats() { Console.WriteLine("Meubel geplaatst"); } } class Kast : Meubel { public void open() { Console.WriteLine("Kast geopend"); } } class ServiesKast : Kast { new public void open() { Kast k = new Kast(); k.open(); } } class Bank : Meubel { } static class MeubelCheckerHelper { public static String openableMeubels = "meubeltestcase.Kast;meubeltestcase.ServiesKast"; public static bool isOpenableMeubel(Meubel meubel) { foreach (String meubelclass in openableMeubels.Split(';')) { if (meubel.GetType().ToString() == meubelclass) { return true; } } return false; } } class Program { static void Main(string[] args) { Kast meubel1 = new Kast(); ServiesKast meubel2 = new ServiesKast(); List<Meubel> meubels = new List<Meubel>(); meubels.Add(meubel1); meubels.Add(meubel2); foreach (Meubel m in meubels) { if (MeubelCheckerHelper.isOpenableMeubel(m)) { foreach (String meubelclass in MeubelCheckerHelper.openableMeubels.Split(';')) { if (meubelclass == "meubeltestcase.Kast") { Kast kast = (Kast)m; kast.open(); } } } } Console.ReadKey(); } } |
Het grote voordeel van interfaces is juist dat je nog een gedeelte van je abstractie bewaard en dat je er dus eventueel meerdere tegelijk kan invoeren. Dan heb je iets als "ZitbareMeubelKist implements Seatable, Openable, Rollable" wat je dan vervolgens kan testen op instanceof Seatable, danwel Openable of Rollable... Hoe meer van dat soort "labels" aan een object te hangen zijn, hoe lastiger het wordt om een starre hierarchie aan te houden.
Jouw string-check is enkel een vervanger voor de instanceof op een te diep niveau en voegt verder niet zoveel toe. Nouja, hoofdpijn zodra je dingen wilt refactoren. Want if(m instanceof Openable) vangt ook gelijk die te openen meubelkist af, terwijl jij er een elseif bij moet zetten.
Jouw code is nu equivalent aan if(m instanceof Kast), alleen dan zonder de daarvoor aangerijkte hulpmiddelen uit de taal zelf.
[ Voor 6% gewijzigd door ACM op 06-04-2011 20:52 ]
Je hebt gelijk, ik kwam erachter dat dit inderdaad niet klopte, hier is een nieuwe versie:Amras schreef op woensdag 06 april 2011 @ 20:47:
Waarom maakt een Servieskast een nieuwe Kast en opent deze, terwijl er wordt gevraagd om de Servieskast te openen?
In deze versie kan je categorieen aangeven, zoals een kast of deur. Als de applicatie dan ziet dat de classname het woord "Kast" bevat, dan weet hij dat de superclass een kast is.
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
| public class Meubel { public void plaats() { Console.WriteLine("Meubel geplaatst"); } } class Kast : Meubel { public void open() { Console.WriteLine("Kast geopend"); } } class ServiesKast : Kast { } class Bank : Meubel { } static class MeubelCheckerHelper { public static String openableMeubels = "kast;deur"; public static bool isOpenableMeubel(Meubel meubel) { foreach (String meubelclass in openableMeubels.Split(';')) { if (meubel.GetType().ToString().ToLower().Contains(meubelclass.ToLower())) { return true; } } return false; } } class Program { static void Main(string[] args) { Kast meubel1 = new Kast(); ServiesKast meubel2 = new ServiesKast(); List<Meubel> meubels = new List<Meubel>(); meubels.Add(meubel1); meubels.Add(meubel2); foreach (Meubel m in meubels) { if (MeubelCheckerHelper.isOpenableMeubel(m)) { foreach (String meubelclass in MeubelCheckerHelper.openableMeubels.Split(';')) { if (m.GetType().ToString().ToLower().Contains("kast")) { Kast kast = (Kast)m; kast.open(); } } } } Console.ReadKey(); } } |
[ Voor 4% gewijzigd door Big Joe op 06-04-2011 21:01 ]
Je hoeft alleen maar instanceof te doen als je te maken hebt met de generieke verzameling meubels. Als je een Opener class hebt die een collectie Openables beheert, kun je daar prima Kasten (implements Openable) aan toevoegen.Woy schreef op woensdag 06 april 2011 @ 19:57:
[...]
Hoe zie je het dan voor je? Natuurlijk is een Kamer ( o.i.d. ) niet de aangewezen class om meubels te openen, maar als er bijvoorbeeld een Persoon is die dat zou doen, dan moet die alsnog uit de kamer alle IOpenable objecten verkrijgen, en dan heb je daar alsnog iets van instanceof voor gebruiken.
Of je loopt te trollen, of je hebt een plaat voor je kop die ze in Japan graag zouden willen hebben om die reactors af te schermen...Big Joe schreef op woensdag 06 april 2011 @ 20:52:
[...]
Je hebt gelijk, ik kwam erachter dat dit inderdaad niet klopte, hier is een nieuwe versie:
Dit kun je niet serieus menen.

[ Voor 45% gewijzigd door Herko_ter_Horst op 06-04-2011 20:56 ]
"Any sufficiently advanced technology is indistinguishable from magic."
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
| using System; using System.Collections.Generic; namespace MeubelOO { interface IOpenable { void Open(); } interface ISittable { void SitOn(); } interface IRollable { void Roll(); } interface ILockable { void ToggleLock(); } abstract class Meubel { public double Width { get; set; } public double Height { get; set; } } class Kast : Meubel, IOpenable { public void Open() { Console.WriteLine(this.GetType().Name + ": Ik ben nu open."); } } class Dressoir : Kast { } class Archiefkast : Kast { } class Kantoorkast : Archiefkast, ILockable { public bool IsLocked { get; private set; } public void ToggleLock() { Console.WriteLine(this.GetType().Name + (IsLocked ? ": Ik ben van het slot gehaald." : ": Ik ben op slot gedaan.")); IsLocked = !IsLocked; } } class Stoel : Meubel, ISittable { public void SitOn() { Console.WriteLine(this.GetType().Name + ": Iemand zit nu op mij."); } } class Bureaustoel : Stoel, IRollable { public void Roll() { Console.WriteLine(this.GetType().Name + ": They see me rollin'"); } } class LuxeBureaustoel : Bureaustoel { } class Program { static void Main(string[] args) { var alleMeubels = new List<Meubel> { new Kast(), new Dressoir(), new Archiefkast(), new Kantoorkast(), new Stoel(), new Bureaustoel(), new LuxeBureaustoel() }; foreach (var meubel in alleMeubels) { if (meubel is IOpenable) { ((IOpenable)meubel).Open(); } if (meubel is ISittable) { ((ISittable)meubel).SitOn(); } if (meubel is IRollable) { ((IRollable)meubel).Roll(); } if (meubel is ILockable) { ((ILockable)meubel).ToggleLock(); } } Console.ReadKey(); } } } |
Kast: Ik ben nu open. Dressoir: Ik ben nu open. Archiefkast: Ik ben nu open. Kantoorkast: Ik ben nu open. Kantoorkast: Ik ben op slot gedaan. Stoel: Iemand zit nu op mij. Bureaustoel: Iemand zit nu op mij. Bureaustoel: They see me rollin' LuxeBureaustoel: Iemand zit nu op mij. LuxeBureaustoel: They see me rollin'
Ik zie echt niet in hoe je dit efficiënt kunt bereiken zónder te kijken of een bepaalde interface geïmplementeerd wordt. Dat gedoe met strings is wel enorm lelijk en zeker niet zaligmakend, zie mijn voorbeeldje met een Dressoir. Het is zeker een kast, maar er zit geen Kast in de naam.
We are shaping the future
Zo dus nu kan ik ook boeken in mijn KasteelBig Joe schreef op woensdag 06 april 2011 @ 20:52:
[...]
Je hebt gelijk, ik kwam erachter dat dit inderdaad niet klopte, hier is een nieuwe versie:
In deze versie kan je categorieen aangeven, zoals een kast of deur. Als de applicatie dan ziet dat de classname het woord "Kast" bevat, dan weet hij dat de superclass een kast is.
Maar hoe komt die Opener aan de collectie? Waarschijnlijk word er op een bepaald moment bedacht dat alle Openable objecten in een Kamer geopend moeten worden ( Of alleen de eerste Container die Openable is waar genoeg ruimte is om iets in op te bergen ). Bij het creëren van de objecten, of het toevoegen aan de Kamer weet je immers nog niet wat er allemaal met de objecten gaat gebeuren.Herko_ter_Horst schreef op woensdag 06 april 2011 @ 20:54:
[...]
Je hoeft alleen maar instanceof te doen als je te maken hebt met de generieke verzameling meubels. Als je een Opener class hebt die een collectie Openables beheert, kun je daar prima Kasten (implements Openable) aan toevoegen.
Nogmaals: Het is goed om te zorgen dat je collectie niet te generiek is, maar je ontkomt er gewoon niet altijd aan.
“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”
En inderdaad, zoals hierboven al gezegd, ga je dan nat bij een Kasteel. Seriously; je hebt drastisch (bij)scholing nodig als je ervan overtuigd bent dat dit goede code is. En zoals anderen al zeiden:je bent misschien best een goede programmeur, maar dit gaat nergens over en is echt beneden peil. Al zit je 50 jaar in 't vak; als je sinds dag 1 niet meer hebt bijgeleerd dan maakt 't je niet nu een goede programmeur. Het spijt me zeer. Op dit vlak moet je gewoon wat leren zo blijkt. Neem dat als een vent en leer er van en doe er iets mee. Daar word je sterker en beter vanBig Joe schreef op woensdag 06 april 2011 @ 20:52:
In deze versie kan je categorieen aangeven, zoals een kast of deur
1
| public static String openableMeubels = "kast;deur"; |
Dit is gewoon een poor-mans wannabe-interface-iets. Gebruik dan gewoon een interface; daar is 't voor.
[ Voor 19% gewijzigd door RobIII op 06-04-2011 22:04 ]
There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.
Je eigen tweaker.me redirect
Over mij
De Opener komt aan de collectie doordat objecten er bij creatie ingestopt worden. Dit is uiteraard afhankelijk van het domein. Je zult dus per domein moeten analyseren wat de juiste aanpak is. Instanceof is daarbij een indicatie dat er mogelijk nog iets scheef zit.Woy schreef op woensdag 06 april 2011 @ 21:49:
[...]
Maar hoe komt die Opener aan de collectie? Waarschijnlijk word er op een bepaald moment bedacht dat alle Openable objecten in een Kamer geopend moeten worden ( Of alleen de eerste Container die Openable is waar genoeg ruimte is om iets in op te bergen ). Bij het creëren van de objecten, of het toevoegen aan de Kamer weet je immers nog niet wat er allemaal met de objecten gaat gebeuren.
Nogmaals: Het is goed om te zorgen dat je collectie niet te generiek is, maar je ontkomt er gewoon niet altijd aan.
Stel dat we het hebben over een tekst-RPG waarin je van Kamer naar Kamer kan gaan. In een Kamer staan Meubels. In een Kamer zijn er ook objecten die open kunnen (c.q. waar de speler mee kan interacteren). Voor de beschrijving zal de Kamer een collectie van Meubels bevatten. Daarnaast bevat de Kamer (of mogelijk een andere klasse) een collectie met Openables. Hierin zitten niet alleen de Kasten (of andere Meubels-die-open-kunnen), maar bijv. ook Boeken, Ramen en Deuren.
Op het moment dat je de Kamer vult, kun je de Kast (die Openable implementeert) simpelweg in beide collecties stoppen.
Iedereen neemt nu die ene generieke collectie van meubels als uitgangspunt. Dan kom je niet zo gauw af van instanceof (of een variant daarop). Je moet naar de requirements kijken om te bepalen of die collectie daar wel terecht staat.
[ Voor 9% gewijzigd door Herko_ter_Horst op 06-04-2011 22:08 ]
"Any sufficiently advanced technology is indistinguishable from magic."
Hoe zie je dat vullen dan voor jeHerko_ter_Horst schreef op woensdag 06 april 2011 @ 22:02:
[...]
Op het moment dat je de Kamer vult, kun je de Kast (die Openable implementeert) simpelweg in beide collecties stoppen.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| class Kamer { void Add(Meubel m) { meubels.Add(m); //Wat als m hier ook een IOpenable is? } void Add(IOpenable o) { openables.Add(o); //Hoe voeg je hier toe aan meubels? Je weet immers niet zeker of "o" ook een meubel is } } |
Tuurlijk, daar ben ik het met je eens. Als je bij creatie al weet in welke categorieën je het kan indelen, moet je dat zeker niet laten. Maar je komt dit soort situaties IMHO toch regelmatig tegen.Iedereen neemt nu die ene generieke collectie van meubels als uitgangspunt. Dan kom je niet zo gauw af van instanceof (of een variant daarop). Je moet naar de requirements kijken om te bepalen of die collectie daar wel terecht staat.
[ Voor 27% gewijzigd door Woy op 06-04-2011 22:14 ]
“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”
Iemand maakt die Kast. Die weet dus dat Kast zowel een Meubel als een Openable is en kan daarom beide methodes aanroepen.Woy schreef op woensdag 06 april 2011 @ 22:11:
[...]
Hoe zie je dat vullen dan voor je
C#:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Kamer { void Add(Meubel m) { meubels.Add(m); //Wat als m hier ook een IOpenable is? } void Add(IOpenable o) { openables.Add(o); //Hoe voeg je hier toe aan meubels? Je weet immers niet zeker of "o" ook een meubel is } }
"Any sufficiently advanced technology is indistinguishable from magic."
Dat zou kunnen, maar dat is ook foutgevoelig, immers kan er dan een Meubel in de kamer staan die Openable is, maar die door de Opener niet meer geopend kan worden. Als een class immers later alsnog Openable gaat implementeren word er geheid vergeten om die 2e Add aanroep toe te voegen. En je gaat er in dat geval ook van uit dat de gene die de Kast maakt ook degene is die hem in de Kamer plaatst. Misschien komt hij wel uit een MeubelFactory, en voor die class is het niet interessant dat het een Openable is, voor de Kamer blijkbaar wel, en dus zal die daarop moeten controleren.Herko_ter_Horst schreef op woensdag 06 april 2011 @ 22:15:
[...]
Iemand maakt die Kast. Die weet dus dat Kast zowel een Meubel als een Openable is en kan daarom beide methodes aanroepen.
Het staat IMHO netter om in de Kamer class een instanceof te gebruiken, dan om te verplichten dat hij 2x aan de Kamer toegevoegd moet worden.
Het is ook niet dat ik wil zeggen dat je altijd maar instanceof moet gebruiken. Het is best goed om je af te vragen of het op die plek wel de beste oplossing is. Maar ik moet toch zeggen dat ik toch wel regelmatig plekken tegenkom waar ik het gebruik.
[ Voor 25% gewijzigd door Woy op 06-04-2011 22:29 ]
“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”
En een dressoir? Die kan niet geopend worden? En een kastalein daar steek je maar een breekijzer in?Big Joe schreef op woensdag 06 april 2011 @ 20:52:
Je hebt gelijk, ik kwam erachter dat dit inderdaad niet klopte, hier is een nieuwe versie:
In deze versie kan je categorieen aangeven, zoals een kast of deur. Als de applicatie dan ziet dat de classname het woord "Kast" bevat, dan weet hij dat de superclass een kast is.
Ik hoop van harte dat je loopt te trollen. Als je echt denkt dat dit correct ben je gewoon de slechtste Java developer die ik ooit gezien heb, en ik heb een HOOP slechte Java code gezien.
https://niels.nu
Ok, wacht, je zegt iets te geven om de performance van een applicatie, maar toch ga je élke keer een enkele string splitten op ";", die in een array zetten, er overheen lopen, en de array vervolgens weer weggooien.Big Joe schreef op woensdag 06 april 2011 @ 20:12:
Het is een kleine opoffering die je moet maken als je echt om de performance van je applicatie geeft.
Vertel me eens, hoe heeft jouw aanpak precies geholpen met het verbeteren van de performance?
Als je al zo eigenwijs wilt zijn om je eigen "pattern" aan te houden, doe het dan alsjeblieft gewoon zo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| static class MeubelCheckerHelper { public static Type[] openableMeubels = { typeof(Kast), /* ... */ }; public static bool isOpenableMeubel(Meubel meubel) { foreach (Type meubelclass in openableMeubels) { if (meubelclass.IsInstanceOfType(meubel)) { return true; } } return false; } } |
Dan werkt het ook nog als 'meubel' een subclass is van Kast, je kunt naar hartelust refactoren, en het performt ook nog eens een stuk beter.
[ Voor 43% gewijzigd door .oisyn op 06-04-2011 23:22 ]
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.
Maar dan nog heb je het probleem dat je wel weet dat een specifiek meubel te openen is, maar weet je nog niet hoe je hem kunt openen. Dus zul je met reflection of dynamic types aan de gang moeten, of alsnog een interface IOpenable hebben waar je heen kunt casten..oisyn schreef op woensdag 06 april 2011 @ 23:10:
[...]
Dan werkt het ook nog als 'meubel' een subclass is van Kast, je kunt naar hartelust refactoren, en het performt ook nog eens een stuk beter.
1
2
3
4
5
| Meubel b = new Kast(); if(MeubelHelper.IsOpenable(b)) { b.Open();//Compiler error } |
Als je al weet dat het een Kast is dan heeft het geen nut om IsOpenable te doen, en als je het niet weet, dan kun je er niks mee dat hij Openable is ( Behalve als er dus een interface is
“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”
Java variant daarvan is.oisyn schreef op woensdag 06 april 2011 @ 23:10:
Als je al zo eigenwijs wilt zijn om je eigen "pattern" aan te houden, doe het dan alsjeblieft gewoon zo:
C#:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 static class MeubelCheckerHelper { public static Type[] openableMeubels = { typeof(Kast), /* ... */ }; public static bool isOpenableMeubel(Meubel meubel) { foreach (Type meubelclass in openableMeubels) { if (meubelclass.IsInstanceOfType(meubel)) { return true; } } return false; } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| static class MeubelCheckerHelper { public static Class[] openableMeubels = { Kast.class, /* ... */ }; public static bool isOpenableMeubel(Meubel meubel) { for(Class meubelclass: openableMeubels) { if (meubelclass.isInstance(meubel)) { return true; } } return false; } } |
Enige voordeel is dat deze code tenminste nog refactor vriendelijk is.....
Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'
@Janoz: Java kent die vorm van foreach toch niet?
“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”
Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'
Je kan ook generics gebruiken!
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
| package area51; import java.util.LinkedList; import java.util.List; public class Kamer { public static abstract class Meubel {} public static interface Openable { void open(); } public static class Kast extends Meubel implements Openable { @Override public void open() { System.out.println("Kast is geopend"); } } public static class NarniaKast extends Kast { @Override public void open() { System.out.println("Je hebt narnia gevonden"); } } public static class Kist extends Meubel implements Openable { @Override public void open() { System.out.println("Ik kan ook een kist openen"); } } public static void main(String... args) { List<Kast> kasten = new LinkedList<Kast>(); kasten.add(new Kast()); kasten.add(new Kast()); kasten.add(new NarniaKast()); kasten.add(new Kast()); openMeubels(kasten); openMeubels(verzamelOpenableMeubels(new Kast(), new NarniaKast(), new Kist())); } public static <T extends Meubel & Openable> List<T> verzamelOpenableMeubels(T ...ts){ List<T> list = new LinkedList(); for (T t:ts) list.add(t); return list; } public static <T extends Meubel & Openable> void openMeubels(Iterable<T> list){ for (T t:list) t.open(); } } |
owkee, het verdient geen prijs en geeft een paar warnings maar het compiled en het runt
OMG ja daar had ik nog niet eens bij stilgestaan. Dat stuk dat Big Joe na de IsOpenable() dan alsnog gaat kijken of het een Kast is met een specifieke cast had ik ook helemaal gemist. Mijn god, wat heb je er dan überhaupt aanWoy schreef op donderdag 07 april 2011 @ 09:01:
Als je al weet dat het een Kast is dan heeft het geen nut om IsOpenable te doen, en als je het niet weet, dan kun je er niks mee dat hij Openable is ( Behalve als er dus een interface is)

The plot thickens...
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.
Wat is het nou? Hoe kan feedback leveren beneden pijl zijn? Dat jij nog nooit (negatieve) feedback hebt gehad, maakt nog niet dat jij gelijk hebt.Big Joe schreef op woensdag 06 april 2011 @ 20:12:
[...]
Verder vind ik het beneden peil dat jullie mijn code op zo'n negatieve manier afkraken. Ik zit al 15 jaar in het vak en heb nog nooit negatieve feedback gehad op mijn code!
Het betekent alleen dat 'ie geen mensen kent die op hetzelfde niveau of hoger programmeren. En dat is eerder slecht voor je ontwikkeling dan goed... Ik moet er niet aan denken dat ik een weekje voorbij laat gaan zonder kritiek van mijn collega's, laat staan 15 jaar zonder kritiek.Vinnienerd schreef op donderdag 07 april 2011 @ 12:18:
[...]
Wat is het nou? Hoe kan feedback leveren beneden pijl zijn? Dat jij nog nooit (negatieve) feedback hebt gehad, maakt nog niet dat jij gelijk hebt.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.
*kuch* feedback *kuch*Armageddon_2k schreef op donderdag 07 april 2011 @ 13:08:
Ach 't is Kaddafi toch ook prima afgegaan, en die zat een jaar of 40 prima op zn plek zonder commentaar
Sure ... Programma-code is een organisch iets. Requirements veranderen na verloop van tijd, en een naam die gisteren zinnig was, kan morgen plots helemaal nergens meer opslaan. Dan ga je mij niet zeggen dat je bij code-wijzigingen om die veranderende functionaliteit te implementeren, die class niet gaat refactoren en een andere naam geven ...Big Joe schreef op woensdag 06 april 2011 @ 20:12:
[...]
Bij mij op mijn werk gebruiken we het waterval model en is dit niet van toepassingen. Klassendiagrammen en ontwerpen worden van tevoren opgezet met UML, zodat namen vaststaan en nooit zullen veranderen. Het is een kleine opoffering die je moet maken als je echt om de performance van je applicatie geeft.
Of ... Jullie requirements veranderen nooit, en jullie code is gebeiteld in steen ? Eens gereleased komen er nooit nieuwe versies ?
Een ugly implementatie van een instanceof() operator dus ?Een helper is in dit geval een soort controller die de applicatie helpt om te bepalen welke meubelen een kast zijn.
https://fgheysels.github.io/
https://niels.nu
Woy schreef op donderdag 07 april 2011 @ 09:52:
offtopic:
@Janoz: Java kent die vorm van foreach toch niet?
Heeey ... Had Janoz nou eerst echt iets als "foreach" staan en heeft hij dat later gewijzigd zonder dat wij dat kunnen zien of bedoelde Woy nu dat hij de ":" manier van itereren niet kent?Janoz schreef op donderdag 07 april 2011 @ 09:58:
oepsie... Maar deze vorm wel (/me tikt altijd wel foreach om op die manier het eclipse template aan te roepen)
In geval Janoz, foei, in geval Woy, dat zit er in sinds 1.5.
En verder heeft .oisyn he-le-maal gelijk dat je het steeds parsen van strings om iets typeof/instanceof-achtigs te krijgen echt niet moet willen. Gewoon goed gebruik maken van interfaces.
Kijk, onderaan, bij normale stervelingen zie je tenminste wel of er iets in het bericht is gehackt.
[ Voor 17% gewijzigd door Killemov op 08-04-2011 21:47 ]
Hey ... maar dan heb je ook wat!
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.
Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'