8792 sujets

Développement web côté serveur, CMS

Pages :
(reprise du message précédent)

Bonjour,

Antoine Cailliau a bien raison.
Le language orienté object par excellence est bien SmallTalk.
Il est peu utilisé malheureusement, mais son développement est très actif.

Voici un exemple d'application démontrant la puissance de ce language.

http://www.squeak.org/

Une plateforme qui permet de manipuler des objects dans tous les sens via une interface graphique.
Son intérêt est à but éducatif.
Il permet d'expliquer le concept objet tout en s'amusant et de réaliser de véritables applications multimédia.
Quelqu'un n'ayant jamais fait de programmation ou bien un enfant peur l'utiliser tellement qu'il est simple d'utilisation.

Maintenant les enfants vont se mettre à l'orienté objet Smiley biggrin
Julien Royer a écrit :
Bonjour,Pour ma part, je ne trouve pas qu'une fonction statique et abstraite corresponde à une utilisation correcte de la programmation objet. Peut-on avoir un exemple d'un cas où c'est adapté ?


J'ai un exemple si tu veux, mais c'est un peu long ....

Mon site web est découpé en modules, que j'ai naturellement modélisés avec des classes. Bien évidament, ces modules sont des ... modules !! donc je fais un peu de polymorphisme. La classe module n'est pas une interface car, bien qu'abstraite, tous les modules ont une configuration qui est modélisée par une variable privée statique (rappel: les interface n'ont pas de champ). Bref faisons le point :

abstract class module {
  private static $configuration;
}
class forums extends module { }
class articles extends module { }


Bien évidement, tous les modules ont également en point commun de distribuer une liste d'URL afin de peupler un menu, afin de rendre le module totalement indépendant de la structure du site. Ainsi, la génération du menu ressemble à ceci :

foreach ($modules as $module) {
  $module->menu();
}


Cette méthode menu() est évidament commune à tous les modules, il faut donc leur en faire hériter par la classe module. Comme un module DOIT implémenter cette méthode, il faut qu'elle soit déclarée abstraite au niveau de module. Il existe deux solutions. La plus bourrine ressemble à ceci :

abstract class module {
  private static $configuration;
  public abstract function menu ();
}

class forums extends module {
  public function menu() { }
}


En terme de modélisation objet c'est assez moche d'autant que le verbe implémenter aura fait tiqer n'importe quel habitué de la POO. La solution "plus mieux bien" serait celle ci :

interface menuizable {
  function menuize ();
}

abstract class module implements menuizable {
  private static $configuration;
}

class forums extends module {
  public function enuize () { }
}


Malhreusement, le problème est un peu plus compliqué. En effet, tu veux que ton site génère le menu, mais que chaque module ait le même affichage des liens. Ca serait con d'en avoir un qui fait des listes verticales et l'autre qui fait des listes horizontales. Solution ? Utiliser deux méthodes. La première va générer une liste d'URLs, et la seconde va les mettre en forme. La première est spécifique à chaque module, la seconde est générique. Cependant, il n'y a pas de raison que la première, qui génère les URL ne soit utilisée par d'autres classes. En bref, le module va hériter d'une méthode publique finale qui va appeller une autre, protégée qui va lui envoyer les URL. On ne peut plus utiliser les interfaces, car les méthodes d'interfaces sont toujours publiques. Résultat :

abstact class module {
  public final function menu() { }
  protected abstract function urls ();
}

class forum extends module {
  protected function urls () { }
}


Ainsi, il suffit d'appeler forum->menu() pour avoir un zoli menu ! Mais mais mais, un programmeur veut toujours faire plus. Revenons à notre générateur de menu. L'algorithme du foreach fonctionne bien si $modules est un itérable qui contient une liste d'instances. Mais quel est l'intérêt d'instancier tous les modules existants dans le site juste histoire d'avoir l'affichage du menu ? Si tu en as un paquet ça représente sa dose de mémoire. En revanche, il est facile de connaitre le nom des CLASSES disponibles. Tu vois où je veux en venir ? Supposons que $modules ne contient pas des instances mais des chaines remplies du nom des classes de modules ... Il faut appeler la méthode menu statiquement !

foreach ($modules as $module) {
  $module::menu();
}


Bien essayé, mais ça n'existe pas. En fouillant un peu sur php.net ...

foreach ($modules as $module) {
  if ($module instanceof module) {
    call_user_func_array (Array($module, 'menu'), Array());
  }
}

Bingo ! Maintenant, on déclare menu statique un peu partout ...

abstract class module {
  protected abstract function urls ();
  public static final function menu () { }
}

class forum extends module {
  protected function urls () { }
}

Pour appeller la méthode non statique urls(), il va falloir instancier nos modules ce qui finalement ne servirait à rien ! Ainsi on termine en beauté ...

abstract class module {
  protected static abstract function urls ();
  public static final function menu () { }
}

class forum extends module {
  protected function urls () { }
}


Et voila !!

NOTE:
Malheureusement, la déclaration d'une méthode statique abstraite génère une E_STRICT. Rien de bien grave, ce type d'erreur est en dessous du E_NOTICE et n'apparait sur aucune config habituelle. La solution STRICTE est celle ci :

interface menuizable {
  static function urls ();
}

abstract class module implements menuizable {
  public static final function menu () { }
}

class forum extends module {
  public function urls () { }
}


Malheureusment, on est obligés de déclarer urls() publique. Ainsi dans le cas d'une méthode publique, la solution statique + abstraite est contournable. Dans les autres cas, c'est parfois inévitable.
Pages :