[PHP][OOP] Plus propre ?

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…

Any idea ?
Merciiiii

Antoine

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 );
}

FormatAReader implements IFormatReader { … }
FormatBReader implements IFormatReader { … }

FormatReaderFactory
{
static function GetReader( $src )
{
foreach( $class in get_declared_classes() )
{
if( $reader is FormatReader )
{
$reader = new $class();

    if( $reader->CanRead( $src ) )
    {
      return( $reader );
    }
  }
}

return( null );

}
}[/code]

Après il ne te reste plus qu’à faire un DoSomeStuff( Factory::GetReader( $src )->GetData( $src ) );

Edit: Mais tu bossais pas dans le domaine du JV? c’est la première fois que je te vois poser une question sur PHP :).

Reedit: oublié le test pour que la classe fasse partie de l’interface FormatReader

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

WAIT WHAT ? w00t !?

Mouarf, je me disais aussi… :slight_smile:
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 ? :slight_smile: (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 !

Antoine

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

NOMAD SOUL !!!

ok, donc voici la requete d’un fan :

Ne remplacer pas BOWIE par justin timberlake ni kenny west !!! Pitié…

Patryn > ok, ça sera justin biber.

désolé HS.