La statique est mauvaise, mais qu'en est-il du modèle Factory?

13

Je suis sur un projet TDD, donc j'essaie de m'en tenir le plus possible aux bonnes pratiques impliquées dans ce type de développement. L'un d'entre eux évite autant que possible statique et global.

Je suis confronté à ce problème: j'ai un objet "article" qui peut avoir des "options" (des "micro-articles" supplémentaires) qui lui sont liés.

Je ne peux pas comprendre comment avoir une bonne approche qui ne sera pas contre-productive ou générera trop de requêtes parce que je serais dans une situation où tout est tellement découplé que je devrai essentiellement faire 1 requête par objet.

De mon point de vue actuel, je vois 3 options:

1) Construire à l'intérieur de l'article:

class Article
{
    //[...]
    public function getArrOption(){
        //Build an array of Options instance.
        //return an array of Options.
    }
}

Pro: simple

Const: maintenabilité: l'objet article contient désormais la logique de construction de l'objet Option. Cela entraînera probablement une duplication de code.

2) Utilisation d'une optionFactory

class Article
{
    //[...]
    public function getArrOption(){
        return OptionFactory::buildFromArticleId($this->getId());
    }
}

Pro: La logique de construction n'est pas en dehors de la classe Article

Const: J'enfreins la règle "il est difficile de se moquer de la statique", ce qui rend ma classe d'article difficile à tester.

3) Séparez toutes les logiques.

//Build the array of Option instance in a controller somewhere, using a Factory:
$arrOption = OptionFactory::buildFromArticleId($article->getId());

Pro: L'article ne gère que sa propre responsabilité et ne se soucie pas du lien de son "père" avec les options. Les choses sont vraiment découplées

Const: exigera plus de code à l'intérieur du contrôleur à chaque fois que je devrai accéder aux options. Cela signifie que je ne devrais jamais utiliser une usine à l'intérieur d'un objet, et ce genre de son est pour moi une utopie ...

Quelle est la meilleure façon de procéder? (Ai-je raté quelque chose?) Merci.

Éditer:

Sans oublier que si je ne peux pas appeler factory à l'intérieur de la classe, je ne pourrai jamais utiliser le modèle d'initialisation paresseux aussi ...

FMaz008
la source
Je ne sais pas si c'est pertinent, mais je code en PHP, donc "l'application" est sans état. Nous devons recharger toutes les données entre chaque page si elles ne sont pas stockées dans un cookie de session. Cela signifie que nous ne pouvons pas tout pré-charger comme dans un langage d'application.
FMaz008
@job: Eh bien, c'est parce qu'un appel statique à l' intérieur d' une méthode est presque impossible à remplacer lors des tests unitaires. L'objectif est d'utiliser l'injection de dépendance. Mais une usine est généralement statique, elle ne peut donc pas être injectée.
FMaz008

Réponses:

12
  1. La statique n'est pas "mauvaise", elle est imparable. Vous pouvez toujours l'utiliser là où la moquerie n'a pas de sens.

  2. Ce n'est pas un modèle Factory, il ressemble à un modèle Repository, bien qu'il ne le soit pas. Factory est l'endroit où vous avez plusieurs classes avec la même interface / classe de base et vous voulez séparer la logique qui décide de la classe à renvoyer. Le référentiel obtient les données de son référentiel, résumant la mise en œuvre de ce référentiel (l'article n'a pas besoin de savoir si ses options sont stockées dans la même base de données, une autre, un fichier XML, un fichier CSV, etc.).

  3. Vous avez ignoré la possibilité de donner à la classe Article un objet ObjectFactory (ou Repository, ou autre) dans le constructeur sur lequel elle peut appeler la méthode buildFromArticle.

Mon PHP est rouillé, mais je pense qu'il ressemble à ceci:

class Article
{
    private $_option_repository;

    public function __construct($option_repository) {
        $_option_repository = $option_repository;
    }

    //[...]

    public function getArrOption(){
        return $_option_repository->buildFromArticleId($this->getId());
    }
}

Je pense que cela satisfait tous vos pros ci-dessus.

pdr
la source
Donc, c'est ok d'avoir des instances de Factory / Repository / Mapper? J'aurai besoin d'un conteneur de dépendances ou quelque chose parce que si nous devons injecter toute la fabrique / référentiel / mappeur pour tout l'objet possible qui peut être retourné par un objet, cela fait rapidement beaucoup. (Article -> OptionGroup -> Option -> Article, etc.)
FMaz008
1
C'est plus que correct, c'est préférable. Je réserve généralement une utilisation statique à la suppression de code répété, où il est suffisamment petit pour être testé dans plusieurs classes. Et oui, un conteneur IOC / DI va vous simplifier la vie. Utilisez-en un.
pdr
1

Voici une citation tirée d'un article qui affirme que vous n'avez jamais besoin de méthodes statiques, que les usines abstraites ont été prouvées être déroutantes, et suggère un léger changement de langage vers l'injection de dépendance comme solution.

Un couplage étroit entre les instances et leurs classes rompt l'encapsulation et, associé à la visibilité globale des méthodes statiques, complique les tests. En faisant de l'injection de dépendances une caractéristique du langage de programmation, nous pouvons nous débarrasser complètement des méthodes statiques. Nous utilisons les changements sémantiques suivants:

(1) Remplacer chaque occurrence d'un global par un accès à une variable d'instance;

(2) Que cette variable d'instance soit automatiquement injectée dans l'objet lorsqu'elle est instanciée.

"Seuss: découpler les responsabilités des méthodes statiques pour une configurabilité fine"

Wayback Machine Link

nes1983
la source
3
Bien que ce lien puisse répondre à la question, il est préférable d'inclure les parties essentielles de la réponse ici et de fournir le lien de référence. Les réponses de lien uniquement peuvent devenir invalides si la page liée change.
moucher