[js] Interfaces, handige oplossing zo?

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • Rekcor
  • Registratie: Februari 2005
  • Laatst online: 28-06 17:29
JavaScript kent geen natieve implementatie voor interfaces (in de zin van Object Oriented Programming).

Wat vinden jullie van deze implementatie?

http://jsbin.com/ubedej/1/

Het komt er eigenlijk op neer dat je een aantal verplichte functies definieert in een array, en dat je een functie laat checken of jouw object deze functies heeft. Heeft zoiets zin, of moet ik gewoonweg niet met interfaces (willen) werken in JavaScript?

[ Voor 11% gewijzigd door Rekcor op 11-03-2013 20:42 ]


Acties:
  • 0 Henk 'm!

  • sky-
  • Registratie: November 2005
  • Niet online

sky-

qn ella 👌

Is een prima oplossing, maar Javascript kent eigenlijk geen goede implementatie van interfaces. Iedereen doet het op zijn eigen (of geen ;)) manier.

Ik zou gewoon met je code aan de slag gaan, veel uitproberen en refactoren mocht er ergens een probleem voorkomen. Als het uiteindelijk een lastige implementatie wordt kan je de implementatie van interfaces ook droppen en eventueel met overerving van classes aan de slag gaan.

[ Voor 48% gewijzigd door sky- op 11-03-2013 21:13 ]

don't be afraid of machines, be afraid of the people who build and train them.


Acties:
  • 0 Henk 'm!

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 12-07 22:24
Vanwege het flexibele karakter van objecten in JavaScript heb je weinig aan interfaces. Het is namelijk simpelweg onmogelijk om een contract run-time af te dwingen.

Als je het compile-time af wilt dwingen om zo structuur in je eigen codebase (en enkel je eigen codebase!) aan te brengen, dan heb je meer aan het TypeScript initiatief dat een type system bovenop JavaScript zet en de class en module constructies uit ES6 / Harmony implementeert.

Acties:
  • 0 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
Tziet eruit als overhead. Ik zou die controle alleen uitvoeren tijdens het developen als je dat graag wil, elke keer allemaal controle doen tijdens runtime lijkt me zonde van de tijd.

Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 22:15
R4gnax schreef op maandag 11 maart 2013 @ 23:27:
Mijns inziens dient zo'n slecht patroon gewoon geen plaats te hebben in wat voor voorbeeld code dan ook*, want iedere aap die aan het kopiëren slaat, zal het gewoon klakkeloos overnemen en het probleem op die manier verder laten leven. (Sla de geschiedenis van PHP er maar eens op na.)
Het lijkt me makkelijker om een standaard functie te maken waarop je nieuwe functies baseert:

[knip]

Op deze manier erft het Button element functie automatisch de setEnabled functie. Als je dus een base functie maakt met alle eigenschappen die al je functies moeten hebben en deze vervolgens extend dan heb je ook deze zekerheid.

Voor het gemak even alle logic weggehaald want het gaat om het principe

[ Voor 50% gewijzigd door CurlyMo op 11-03-2013 23:34 ]

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 14-07 21:33

NMe

Quia Ego Sic Dico.

Dat is precies het tegenovergestelde van wat een interface doet. Een interface zegt: als je een class afleidt van deze interface dan moet je deze methods implementeren, of je krijgt een error. Jouw suggestie zorgt enkel dat die methods vast voorgedefinieerd zijn. Je legt de verantwoordelijkheid dus elders neer, en dat kan natuurlijk best zin hebben, maar niet als interface-vervanger. :)

PRG>>WEB

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


Acties:
  • 0 Henk 'm!

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 12-07 22:24
CurlyMo schreef op maandag 11 maart 2013 @ 22:12:
Het lijkt me makkelijker om een standaard functie te maken waarop je nieuwe functies baseert:
JavaScript:
1
[snip]


Op deze manier erft het Button element functie automatisch de setEnabled functie. Als je dus een base functie maakt met alle eigenschappen die al je functies moeten hebben en deze vervolgens extend dan heb je ook deze zekerheid.

Voor het gemak even alle logic weggehaald want het gaat om het principe
Laten we even één van de cardinale regels van modern JavaScript breken en gaan morellen aan de prototypes van kern types als Function. :F Dat zet dus echt een vreselijk slecht precedent voor de rest van je codebase. Er is maar één goede reden waarom je dat zou mogen doen: missende functionaliteit aanvullen via een (volgens de afgesproken API werkende) polyfill.

Daarnaast is de methode om classical inheritance te implementeren in JS zoals je die hier presenteert ook echt een absolute draak. Het is afkomstig uit het MS AJAX framework; dat zegt voor velen al genoeg, maar in dit geval is het ook echt terecht. Dat kun je met geen enkel goed recht leesbaar of onderhoudbaar noemen.

Het is eigenlijk vrij simpel om een class factory te koken die werkt via deftige definities op basis van object literals. Combineer dat met AMD (bijv. via RequireJS) voor namespacing en dependency-based includes en je kunt JavaScript 'classes' schrijven haast als ware je in een taal als Java of C# aan het werken. Voilà:

JavaScript: lib/core/Class.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
define({
  create : function( base, proto ) {
    var Ctor, Glue;

    if ( proto == null ) { proto = base; base = Object; }
    
    Glue = function() {};
    Glue.prototype = base.prototype;

    Ctor = proto.hasOwnProperty( "constructor" ) ? proto.constructor : function() {
      return base.apply( this, arguments );
    };
    Ctor.prototype = new Glue();
    Ctor.prototype.constructor = Ctor;

    for ( var name in proto ) {
      if ( name === "constructor" || !proto.hasOwnProperty( name )) continue;
      Ctor.prototype[ name ] = proto[ name ];
    }

    return Ctor;
  }
});


JavaScript: geo/Shape.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
define([ "lib/core/Class" ], function( Class ) {

  var Shape = Class.create({  
    constructor : function( x, y ) {
      this.x = x;
      this.y = y;
    },
    move : function( x, y ) {
      this.x += x;
      this.y += y;
    }
  }); 
  
  return Shape;
});


JavaScript: geo/Rectangle.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
define([ "lib/core/Class", "./Shape" ], function( Class, Shape ) {

  var Rectangle = Class.create( Shape, {
    constructor : function( x, y, width, height ) {
      Shape.prototype.constructor.call( this, x, y );
      this.width = width;
      this.height = height;
    },
    area : function() {
      return this.width * this.height;
    }
  });

  return Rectangle;
});


Hopelijk kunnen we afspreken om die vreselijke, vreselijke troep van het MS AJAX framework niet meer aan andere mensen aan te leren, maar het lekker een stille dood te laten sterven. :)

Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 22:15
R4gnax schreef op maandag 11 maart 2013 @ 23:04:
Hopelijk kunnen we afspreken om die vreselijke, vreselijke troep van het MS AJAX framework niet meer aan andere mensen aan te leren, maar het lekker een stille dood te laten sterven. :)
Laat ik (ooit) iets geschreven hebben wat dus blijkbaar lijkt op MS AJAX, maar ik heb echt daadwerkelijk nog nooit van gehoord. Wat je er dus van mocht vinden staat je vrij, het is vooral bedoeld om een suggestie te doen van hoe je zoiets zou kunnen aanpakken op een andere manier dan via interfaces. Het werkte overigens prima qua snelheid en geheugen gebruik.

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 12-07 22:24
CurlyMo schreef op maandag 11 maart 2013 @ 23:12:
Wat je er dus van mocht vinden staat je vrij, het is vooral bedoeld om een suggestie te doen van hoe je zoiets zou kunnen aanpakken op een andere manier dan via interfaces. Het werkte overigens prima qua snelheid en geheugen gebruik.
Mijns inziens dient zo'n slecht patroon gewoon geen plaats te hebben in wat voor voorbeeld code dan ook*, want iedere aap die aan het kopiëren slaat, zal het gewoon klakkeloos overnemen en het probleem op die manier verder laten leven. (Sla de geschiedenis van PHP er maar eens op na.)

Dat het prima werkt qua snelheid en geheugen gebruik klopt inderdaad. Het werkt immers op basis van prototype methods i.p.v. instance methods, dus je hebt geen replicatie van methods per instance in je geheugen en je hebt niet de extra opstartkosten elke keer wanneer je een class instance aanmaakt. Dat is ook niet waar ik bezwaar op heb. Het is de manier waarop de declaraties voor een class in elkaar steken, die gewoon niet leesbaar en onderhoudbaar is. En het is het lukraak uitbreiden van het prototype van Function voor eigen doeleinden, wat eigenlijk nooit een slim idee is.

* Behalve als je expliciet een voorbeeld wilt geven van hoe je bepaalde dingen niet in JS moet doen, uiteraard.

offtopic:
Even voor de goede orde; het is niet mijn bedoeling om jou als persoon aan te vallen. Je hebt niet beter geweten, en dat kan gebeuren. Zeker als je een tijd niets meer met JS gedaan hebt kan ik me dat indenken, aangezien de laatste tijd JS een enorme vogelvlucht genomen heeft. Ik neem enkel een wat steviger standpunt betr. jouw code sample in zodat het bij iedereen die dit topic later nog eens inkijkt ook goed door dringt.

[ Voor 20% gewijzigd door R4gnax op 11-03-2013 23:39 ]


Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 22:15
R4gnax schreef op maandag 11 maart 2013 @ 23:27:
offtopic:
zeker als je een tijd niets meer met JS gedaan hebt kan ik me dat indenken, aangezien de laatste tijd JS een enorme vogelvlucht genomen heeft.
offtopic:
Deze code is denk ik zo'n 5 jaar oud. Ik zal me niet meer bemoeien met Javascript discussies :)

[ Voor 3% gewijzigd door CurlyMo op 11-03-2013 23:58 ]

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • Rekcor
  • Registratie: Februari 2005
  • Laatst online: 28-06 17:29
@R4gnax: die code ziet er netjes uit! :)

@NMe: misschien is de term 'interface' niet goed. Het probleem wat ik probeer op te lossen is dat ik een framework heb gemaakt wat werkt met plugins. Nu wil ik afdwingen dat plugins tenminste een aantal publieke functies bevatten, op straffe van foutmeldingen.

Acties:
  • 0 Henk 'm!

  • Erwin537
  • Registratie: December 2008
  • Laatst online: 02:32
Ook niet helemaal de oplossing, maar is het dan geen idee om het te schrijven in Typescript of Dart? Deze hebben volgens mij wel interfaces. Tijdens runtime wordt het alsnog niet gechecked natuurlijk, maar dat valt toch wel te omzeilen.

Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 14-07 21:33

NMe

Quia Ego Sic Dico.

Rekcor schreef op dinsdag 12 maart 2013 @ 08:21:
@NMe: misschien is de term 'interface' niet goed. Het probleem wat ik probeer op te lossen is dat ik een framework heb gemaakt wat werkt met plugins. Nu wil ik afdwingen dat plugins tenminste een aantal publieke functies bevatten, op straffe van foutmeldingen.
Dat is juist wel een redelijk goede omschrijving van wat een interface in de praktijk doet. :P Mijn commentaar ging dan ook niet over jouw vraag maar over CurlyMo's oplossing.

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


Acties:
  • 0 Henk 'm!

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 12-07 22:24
Rekcor schreef op dinsdag 12 maart 2013 @ 08:21:
@NMe: misschien is de term 'interface' niet goed. Het probleem wat ik probeer op te lossen is dat ik een framework heb gemaakt wat werkt met plugins. Nu wil ik afdwingen dat plugins tenminste een aantal publieke functies bevatten, op straffe van foutmeldingen.
Bij gebrek aan interfaces kun je werken met classes op basis van de prototype keten. Als je via de prototype keten je plugin classes correct afleidt van een base class, dan kan de instanceof operator je stukken betere runtime veiligheid geven dan enkel te controleren of een object alle methods beschikbaar heeft uit een arraytje namen.

In dat opzicht had CurlyMo wel gewoon gelijk dat je er (een beetje) type safety mee af kunt dwingen.

[ Voor 6% gewijzigd door R4gnax op 12-03-2013 19:04 ]

Pagina: 1