7
votes

Principe ouvert / fermé - Comment faire face à cet interrupteur?

J'ai regardé dans le principe fermé ouvert et ça sonne bien et je voulais donc exercer ses enseignements. J'ai examiné l'application de ma nouvelle connaissance trouvée à un projet existant et je suis devenu un peu coincé tout de suite.

Si un nouvel Usertype vient (et c'est très probable), cela devra être changé, il n'est pas encore fermé modifier. Comment pourrait-on aller autour de cela?

de ce que j'ai lu, cela ressemble à je devrais mettre en œuvre une usine ici au lieu d'appliquer l'OCP?

usine qui enfreint le principe ouvert et fermé xxx

merci, Kohan


0 commentaires

4 Réponses :


5
votes
internal class UserTreeBuilder
{
    [ImportMany(AllowRecomposition=true)]
    public IEnumerable<IBuilder> Builders{ get; set; }

    public UserTreeBuilder()
    {
        // Load all builders from a MEF CompositionContainer
    }

    public void BuildUserTree(User user)
    {
        var builder = Builders.FirstOrDefault(b => b.CanHandleUserType(user.UserType));

        if(builder == null)
        {
            throw new Exception("No UserType set");
        }else{
            builder.BuildTree();
        }
    }
}
The list of available builders could be build using MEF

1 commentaires

+1 pour l'usine dynamique. Voir aussi .



8
votes

Comme tout «principe» OCP n'est pas une règle que vous devez obéir à toutes les occasions.

On nous a dit de «favoriser la composition sur l'héritage», et pourtant les motifs tels que le décorateur et le composite favorisent ouvertement l'héritage.

De même, on nous dit de «programmer une interface, pas une implémentation, et pourtant, à un moment donné de notre application, nous devrons instancier un objet concret de certaines description.

Votre solution est un idiome d'usine classique (si ce n'est pas tout à fait la méthode d'usine complète ou le motif d'usine abstrait). C'est ce qu'il est destiné à faire. Essayer d'appliquer OCP à cela n'a pas de sens.

En fait, en créant cette méthode, vous pouvez en réalité faciliter OCP dans une autre partie de votre base de code. Certaines autres classes ou classes de votre application pourraient maintenant obéir à OCP maintenant, vous avez séparé la création.


3 commentaires

Point juste, je pensais autant. C'est juste lorsque vous apprenez quelque chose de nouveau, vous sortez et essayez de utiliser la connaissance immédiatement pour la sauvegarder dans votre esprit. Je vais continuer à chercher une section de code plus appropriée pour reporter. Acclamations.


Pas de soucis. Bon exercice de pensée pour moi aussi. Je suis aussi dans le processus d'apprentissage des modèles :-)


Bien que ce soit vrai que ceux-ci ne soient pas et ne devraient pas être des règles strictes, les commutateurs sont souvent mauvaises odeurs et d'autres conceptions / motifs pourraient être favorisés qui sont beaucoup plus respectueux de OCP sans inconvénient négatifs. De même, BC, vous avez mentionné cela, j'essaie personnellement d'utiliser des interfaces partout où je peux (sans danger pour l'instanciation qui peut même parfois être faite à travers l'injection de dépédence et la même chose).



2
votes

Pour éliminer le commutateur de type, vous devez déplacer les responsabilités du type nécessitant une action spécifique de type. Ce type, dans votre cas, l'utilisateur a toutes les informations concernant lui-même et peut facilement appeler le bon fonctionnement en fonction de ces connaissances. Et vous devez utiliser l'héritage.

Dans votre cas, vous devrez refléter les types d'utilisateurs via une héritage simple ou via une composition. Votre "utilisateur" serait que d'avoir une propriété "USERTYPE", comme dans votre exemple, mais au lieu de le faire juste un type "ENUM", il devient un type complexe qui hérite d'une interface "IUSERType" et sait comment construire sa société dépendances ("Usertype" implémente "iusertype"). Le "Iusertype" pourrait exposer des attributs spécifiques à un type via une propriété (par exemple. IuseType.Typeespecifictree "qui renvoie une" iTYPespecificTree ").

Alors, quand dans votre exemple, un "utilisateur" est promu Premium, vous pouvez simplement définir la propriété sur une nouvelle instance de la mise en œuvre "IUSERTyType" concrete (par exemple, PremiumUserSerType ") qui exécute ses actions spécifiques telles que la construction de l'arbre de qualité supérieure ( une implémentation "iTYPespecificTree") de votre exemple ainsi que la construction de types associés.

De cette façon, l'instruction de commutation est éliminée à l'aide de la composition et de l'héritage. Nous avons transformé la propriété complexe "USERTYPE" en une classe distincte, puis déplacés des responsabilités spécifiques au type lui-même. L'héritage et l'inverversion surtout de la dépendance a contribué à fonctionner sur un objet (par exemple, obtenir des informations spécifiques de type utilisateur telles que (utilisateur.IuserType.IuserspecificTree ") sans connaître le type de béton. Cela a permis de nous assurer que nous sommes ouverts à l'extension . L'héritage a également contribué à encapsuler un comportement spécifique de type pour rendre notre code proche de la modification .

Si nous devons apporter des modifications à la manière dont l'arborescence spécifique de type est générée ou comment ce type d'utilisateur se comporte, nous ne toucherions que la mise en œuvre "IUSERType" associée, mais jamais l'utilisateur ". Si de nouveaux types d'utilisateurs sont ajoutés (extension), ils devront mettre en œuvre l'interface de base "iuseType" et aucun autre code, comme les instructions de commutation, doivent être touchées pour le faire fonctionner et plus de chèques de type sont nécessaires. Et pour le rendre complet et offrir une certaine extensibilité, la classe "utilisateur" doit également mettre en œuvre une interface par exemple. "Iuer" qui expose le type d'utilisateur (par exemple "iUser.IuserType").


0 commentaires

4
votes

Je ferais comme ci-dessous: xxx pré>

puis au lieu d'une méthode et un boîtier de commutation à modifier chaque fois que vous ajoutez un nouveau type d'utilisateur et d'appeler simplement: P>

user.buildTree();


2 commentaires

Laisser les enfants mettre en œuvre leurs besoins sont un moyen essentiel de mettre en œuvre OCP.


Je pense que le problème principal est que les enfants ajoutant simplement un nouveau contenu. Comme si vous créez un document, vous devez ajouter le titre de champ, l'auteur, la date, etc., donc à la fin, vous avez un article.