Non, je pensais plutôt à sortir la fonction de la méthode dans laquelle elle est coincée (ne pas passer par une fonction anonyme donc), et documenter cette fonction, pour ainsi pouvoir changer de fonction facilement, et isoler les morceaux de code qui peuvent l'être.
"Reprendre l'exemple East": donc reprendre le tiens avec Command? Cela donnerai, en gros, cela (en jouant sur les espaces de nom pour que Command1 et Command2, spécifiques à la classe "...", soient isolées du reste du projet pour ne pas le polluer):
Et findMetadataForTable() est en charge d'appeler "->run()" sur l'objet commande qu'on lui a passé au lieu d'appeler la callback. Pour les paramètresà envoyer à run(), ils sont passés par findMetadataForTable() et lors de l'appel à build(), tout dépend de quels paramètres on veut passer.
Ainsi, on a la possibilité de changer le contenu des fonctions exécutées (les méthodes run()). On peut aussi changer la factory, histoire de générer d'autres objets de commandes.
Okay, cela complexifie la lecture du flux d'exécution mais c'est parfaitement normal: seul le procédural permet de suivre bien proprement un flux d'exécution, l'objet est bien plus émergent et laisse donc une place large à la combinatoire qui est fâchée avec les flux d'exécutions prévisibles et débuggables On peut choisir de faire du "procédural caché dans des classes", pour essayer d'avoir les avantages de l'objet (indépendance des classes) et ceux du procédural (flux d'exécution simple à suivre).
Une programmation objet "parfaite" laisse la place large à l'émergence (comme la réalité: on peut utiliser une tringle à rideau comme tuteur de jardin). Paradoxalement, un programme "bien codé objet" est un programme qui bug, puisqu'il laisse émerger des comportements qui, pour certains, peuvent être indésirables; l'idéal étant alors d'être capable de distinguer les bons et mauvais comportements qui émergeront et de rattraper ces derniers.
Mais attention: la classe que tu proposes est parfaitement valide (enfin, si elle marche); c'est seulement s'il vient le moment où il faut étendre ses possibilités que le découpage se justifie. Sur-découper sans en avoir besoin, pour avoir des moissons de classes, ce n'est pas utile. Découper parce qu'on souhaite modifier le comportement d'une classe ou permettre sa modification (si API ou dev en équipe par exemple), c'est justifié.
"Reprendre l'exemple East": donc reprendre le tiens avec Command? Cela donnerai, en gros, cela (en jouant sur les espaces de nom pour que Command1 et Command2, spécifiques à la classe "...", soient isolées du reste du projet pour ne pas le polluer):
class Command1
{
public function run($metadata, $column, &$result, &$metadataList)
{
$metadataList[$column['table']] = $metadata;
$result[$column['table']] = $metadata->createObject();
}
}
class Command2
{
public function run(&$result, $column)
{
$result[$column['table']] = new \stdClass();
}
}
class ...
{
public function hydrate($columns = array())
{
$result = array();
$metadataList = array();
$factory1 = new FactoryCommand1();
$factory2 = new FactoryCommand2();
foreach ($columns as $column)
{
if ($column['table'] === '')
$column['table'] = 'db__table';
if (isset($result[$column['table']]) === false)
{
$command1 = $factory1->build();
$command2 = $factory2->build();
$this->metadataRepository->findMetadataForTable($column['orgTable'], $command1, $command2);
}
if (isset($metadataList[$column['table']]) === true && $metadataList[$column['table']]->hasColumn($column['orgName']))
{
$metadataList[$column['table']]->setObjectProperty(
$result[$column['table']],
$column['orgName'],
$column['value']
);
}
else
{
$property = 'db__' . $column['name'];
$result[$column['table']]->$property = $column['value'];
}
}
return $result;
}
}
Et findMetadataForTable() est en charge d'appeler "->run()" sur l'objet commande qu'on lui a passé au lieu d'appeler la callback. Pour les paramètresà envoyer à run(), ils sont passés par findMetadataForTable() et lors de l'appel à build(), tout dépend de quels paramètres on veut passer.
Ainsi, on a la possibilité de changer le contenu des fonctions exécutées (les méthodes run()). On peut aussi changer la factory, histoire de générer d'autres objets de commandes.
Okay, cela complexifie la lecture du flux d'exécution mais c'est parfaitement normal: seul le procédural permet de suivre bien proprement un flux d'exécution, l'objet est bien plus émergent et laisse donc une place large à la combinatoire qui est fâchée avec les flux d'exécutions prévisibles et débuggables On peut choisir de faire du "procédural caché dans des classes", pour essayer d'avoir les avantages de l'objet (indépendance des classes) et ceux du procédural (flux d'exécution simple à suivre).
Une programmation objet "parfaite" laisse la place large à l'émergence (comme la réalité: on peut utiliser une tringle à rideau comme tuteur de jardin). Paradoxalement, un programme "bien codé objet" est un programme qui bug, puisqu'il laisse émerger des comportements qui, pour certains, peuvent être indésirables; l'idéal étant alors d'être capable de distinguer les bons et mauvais comportements qui émergeront et de rattraper ces derniers.
Mais attention: la classe que tu proposes est parfaitement valide (enfin, si elle marche); c'est seulement s'il vient le moment où il faut étendre ses possibilités que le découpage se justifie. Sur-découper sans en avoir besoin, pour avoir des moissons de classes, ce n'est pas utile. Découper parce qu'on souhaite modifier le comportement d'une classe ou permettre sa modification (si API ou dev en équipe par exemple), c'est justifié.