Yo! les geeks,
J’ai un petit doute sur une mise en place OOP. Je suis en train de faire un parser de fichiers de divers formats, et avec des opérations différentes à faire au moment du parsing.
Mon point de départ est :
abstract class Parser
{
abstract protected function DoSomeStuff($data);
public function Parse($src)
{
if ( $this->GetFormat($src) == 1 )
{
$data =$this->GetSomeDataFromFormat1($src);
DoSomeStuff($data);
}
if ( $this->GetFormat($src) == 2 )
{
$data = $this->GetSomeDataFromFormat2($src);
DoSomeStuff($data);
}
}
}
class DoSomething extends Parser
{
protected function DoSomeStuff($data)
{
// Doing some stuff with data
}
}
class DoSomethingElse extends Parser
{
protected function DoSomeStuff($data)
{
// Doing some other stuff with data
}
}
$ds = new DoSomething();
$ds->Parse(...);
$dse = new DoSomethingElse();
$dse->Parse(...);
Nous avons donc une classe Parser qui appellera des méthodes abstraites en fonction du format qu’on lui donne. Ces méthodes feront diverses choses en fonction des besoins. Nous avons donc deux dimensions : le format, et les choses à faire. Pour le moment, je suis sur une seule dimension : les choses à faire. La notion de format est gérée dans la classe Parser avec des choses comme GetSomeDataFromFormat1 et GetSomeDataFromFormat2 et je n’aime pas trop ça.
Seulement, je ne vois pas comment faire plus propre… En C++ et héritage multiple je pourrais jongler, mais en simple, je bloque…
Alors, ma suggestion: il te faut un GetFormat qui renvoie un format qui est passé a une classe de type Factory qui va te construire l’objet contenant la méthode GetData().
Par exemple
[code]IFormatReader
{
function CanRead( $src );
function GetData( $src );
}
Hello !
Je réponds à côté volontairement parce que j’ai posé ma question sur StackOverflow, et c’est revenu avec une solution que j’aime bien : le Strategy Pattern. Je vais étudier ta réponse pour comparer. Merci en tous cas !
Et sinon, j’ai arrêté le JV depuis 10 ans maintenant… Mais il se peut que j’y retourne temporairement prochainement… Sur The Nomad Soul (mais ce jeu ne me lâchera donc jamais ??)
Je reviens sur le Strategy Pattern :
interface IActions
{
public function DoSomeStuff();
}
class DoSomething implements IActions
{
public function DoSomeStuff()
{
// imprimer à l'écran par exemple
}
}
class DoSomethingElse implements IActions
{
public function DoSomeStuff()
{
// imprimer sur papier comme autre exemple
}
}
class FileParser
{
protected $actions;
public function __construct(IActions $actions)
{
$this->actions = $actions;
}
/*
Attention, c'est une variation perso du Strategy Pattern :
en principe, il y a une encapsulation supplémentaire à ce niveau.
On devrait avoir en plus :
public function DoSomeStuff()
{
$this->actions->DoSomeStuff();
}
Mais je ne vois pas trop l'intérêt (pour le moment).
*/
}
class Format1Parser extends FileParser
{
public function Parse()
{
// Là on fait des trucs spécifiques au format1
$this->actions->DoSomeStuff();
/*
Suite de la remarque sur ma variation perso :
Le code ici devrait être donc $this->DoSomeStuff();
*/
}
}
class Format2Parser extends FileParser
{
public function Parse()
{
// Là on fait des trucs spécifiques au format2
echo "Format2Parser::Parse\n";
$this->actions->DoSomeStuff();
}
}
class Parser
{
public function __construct($src,$todo)
{
/*
Note pour PERECil : en fait je m'occupais pas trop de GetFormat au départ.
C'était juste là pour les explications.
Mais je vais y regarder de plus près avec ton histoire de Factory.
*/
if ( $this->GetFormat($src) == 1 )
{
$parser = new Format1Parser($src,$todo);
}
if ( $this->GetFormat($src) == 2 )
{
$parser = new Format2Parser($src,$todo);
}
$parser->Parse();
}
}
$parser = new Parser($file1,new DoSomething());
$parser = new Parser($file2,new DoSomethingElse());
Ma technique de Factory, du moins comme je l’ai implémentée ici, t’évites de revenir dans le code du Parser pour implémenter un nouveau FormatParser; la la factory va te trouver automatiquement, parmi les classes déclarées en tant que FormatReader, laquelle correspond. Sinon, pour le reste, c’est kif kif bourricot (ptet un peu plus lent chez moi, vu que je fais de la Reflection à tour de bras).
Mouarf, je me disais aussi…
Je ne peux rien dire, et de toutes façons il y a 95% de chances pour qu’il ne se passe rien. Et puis d’abord qu’est ce qu’il pourrait bien se passer hein ? (je veux pas d’emmerdes avec Quantic et David moi !)
Néanmoins, je suis impressionné de voir qu’il y a des gens qui sont encore à fond sur le jeu 10 ans plus tard.
J’ai été contacté plusieurs fois par des fans qui cherchaient à obtenir les sources, les data, les tools, de la documentation… Etonnant !
han ca me plairait trop ! j’avais vraiment surkiffé the nomad soul ! Au fait, pourquoi tu as arreté la prog de JV à l’epoque ?
Sinon, pour repondre à ta question, pourquoi tu surcharges pas ton DoSomeStuff ? Tu declares plusieurs versions de ta methode qui prends des parametres de type differents, et la bonne classe sera automatiquement prise en fonction de ce que tu passes.
class Parser
{
public function Parse(Type_A $src)
{
// je fais des trucs avec ma src de type_A
}
public function Parse(Type_B $src)
{
// je fais des trucs avec ma src de type_B
}
public function Parse(Type_C $src)
{
// je fais des trucs avec ma src de type_C
}
}
Parser monParser = new Parser()
monParser.Parse(tutu) // en fonction du type de tutu, il executera la fonction qui correspond.
En tout cas, c’est comme ca que je ferai, mais il y a peut etre mieux avec les langages modernes