Question

J'ai eu une discussion au travail en ce qui concerne « l'héritage dans le modèle de domaine complique la vie des développeurs ». Je suis un programmeur OO alors j'ai commencé à chercher des arguments ayant l'héritage dans le modèle de domaine facilitera la vie des développeurs en fait au lieu d'avoir des commutateurs dans tous les sens.

Ce que je voudrais voir est la suivante:

class Animal {

}

class Cat : Animal {

}

class Dog : Animal {

}

Ce que l'autre collègue dit est:

public enum AnimalType {
    Unknown,
    Cat,
    Dog
}

public class Animal {

    public AnimalType Type { get; set; }

}

Comment puis-je le convaincre (les liens sont BIENVENUE ) qu'une hiérarchie de classes serait mieux que d'avoir une propriété ENUM pour ce genre de situations?

Merci!

Était-ce utile?

La solution

Voici comment je raisonne à ce sujet:

Seul héritage utilisation si le rôle / type ne changera jamais. par exemple.

en utilisant l'héritage pour des choses comme:

Pompier <- Employé <-. Personne ne va pas

dès que Freddy le pompier change d'emploi ou se trouve au chômage, vous devez le tuer et de recréer un nouvel objet du nouveau type avec toutes les anciennes relations qui s'y rattachent.

Alors la solution naïve au problème ci-dessus serait de donner une propriété JobTitle ENUM à la classe personne. Cela peut être suffisant dans certains scénarios, par exemple si vous n'avez pas besoin des comportements très complexes associés au rôle / type.

La façon plus correcte serait de donner à la classe personne une liste de rôles. Chaque rôle représente par exemple un emploi avec un intervalle de temps.

par exemple.

freddy.Roles.Add(new Employement( employmentDate, jobTitle ));

ou si cela est exagéré:

freddy.CurrentEmployment = new Employement( employmentDate, jobTitle );

De cette façon, Freddy peut devenir un développeur w / o nous avoir à le tuer d'abord.

Cependant, tous mes divagations ont toujours pas répondu si vous devez utiliser une hiérarchie ou le type ENUM pour le jobTitle.

En pur mem Oo Je dirais qu'il est plus correct d'utiliser l'héritage pour les jobtitles ici.

Mais si vous faites mappings O / R vous pourriez vous retrouver avec un peu modèle de données overcomplex dans les coulisses si le mappeur essaie de retrouver chaque sous-type à une nouvelle table. Donc, dans ce cas, je vais souvent à l'approche enum s'il n'y a pas de comportement réel / complexe associé aux types. Je peux vivre avec un « si le type == JobTitles.Fireman ... » si l'utilisation est limitée et il rend les choses easer ou moins complexes.

par exemple. Entity Framework 4 concepteur pour .NET ne peut mapper chaque sous-type à une nouvelle table. et vous pourriez obtenir un modèle laid ou beaucoup de jointures lorsque vous interrogez votre base de données w / o un avantage réel.

Cependant, je fais l'héritage d'utilisation si le type / rôle est statique. par exemple. pour les produits.

vous pourriez avoir CD <- produit et livre <- Produit. L'héritage gagne ici parce que dans ce cas, vous avez probablement état différent associé aux types. CD peut avoir un certain nombre de pistes propriété alors qu'un livre peut avoir un nombre de biens pages.

Donc en bref, cela dépend; -)

En outre, à la fin de la journée, vous sera très probablement se retrouver avec beaucoup d'instructions switch ou l'autre manière. Disons que vous voulez modifier un « produit », même si vous utilisez l'héritage, vous aurez probablement le code comme ceci:

si (produit Livre)         Response.Redicted ( "~ / EditBook.aspx id?" + Product.id);

Parce que l'encodage URL édition de livre dans la classe d'entité serait simplement laid car il forcerait vos ENTITES d'affaires à connaître votre structure du site, etc.

Autres conseils

énumérations sont bien quand:

  1. L'ensemble des valeurs est fixe et ne change ou très rarement.
  2. Vous voulez être en mesure de représenter une union de valeurs (à savoir combinant drapeaux).
  3. Vous n'avez pas besoin d'attacher un autre état à chaque valeur. (Java ne possède pas cette limitation.)

Si vous pouviez résoudre votre problème avec un certain nombre, un ENUM est probablement un bon ajustement et plus sûr du type. Si vous avez besoin de plus de flexibilité que ce qui précède, alors énumérations sont probablement pas la bonne réponse. L'utilisation de classes polymorphes, vous pouvez:

  1. statiquement veiller à ce que tous les comportements spécifiques de type est traité. Par exemple, si vous avez besoin tous les animaux pour pouvoir Bark(), des cours de fabrication de Animal avec une méthode abstraite de Bark() va laisser le contrôle du compilateur pour vous que chaque sous-classe implémente. Si vous utilisez un ENUM et un grand switch, il ne garantit pas que vous avez traité tous les cas.

  2. Vous pouvez ajouter de nouveaux cas (types d'animaux dans votre exemple). Cela peut se faire à travers les fichiers source, et même à travers les frontières de l'emballage. Avec un ENUM, une fois que vous avez déclaré, il est gelé. l'extension à composition non limitée est l'une des principales forces de la POO.

Il est important de noter que l'exemple de votre collègue n'est pas en opposition directe à la vôtre. S'il veut un type d'animal à être une propriété exposée (qui est utile pour certaines choses), vous pouvez toujours le faire sans utiliser ENUM, en utilisant la balise Type modèle d'objet :

public abstract class AnimalType {
    public static AnimalType Unknown { get; private set; }
    public static AnimalType Cat { get; private set; }
    public static AnimalType Dog { get; private set; }

    static AnimalType() {
        Unknown = new AnimalType("Unknown");
        Cat = new AnimalType("Cat");
        Dog = new AnimalType("Dog");
    }
}

public class Animal {
    public AnimalType Type { get; set; }
}

Cela vous donne la commodité d'un ENUM: vous pouvez faire AnimalType.Cat et vous pouvez obtenir le type d'un animal. Mais il vous donne aussi la flexibilité des classes: vous pouvez ajouter des champs à AnimalType pour stocker des données supplémentaires à chaque type, ajouter des méthodes virtuelles, etc. Plus important encore, vous pouvez définir de nouveaux types d'animaux par la simple création de nouvelles instances de AnimalType

Avoir un ENUM est comme jeter une fête pour tous ces gens Open/Closed Principle is for suckers.

Il vous invite vraiment à vérifier si un animal est d'un certain type et puis appliquer une logique personnalisée pour chaque type. Et cela peut rendre le code affreux qui le rend vraiment difficile de continuer à construire sur votre système.

Le plus important OOPS moyens de modélisation réalité. Héritage vous donne l'occasion de dire chat est un animal. Animal ne devrait pas savoir si son chat crie maintenant et décider qu'il est supposé Meow et non Bark, Encapsulation y sera vaincu. Moins de code que maintenant vous ne pas faire en cas d'autre que vous avez dit.

Les deux solutions sont bonnes. Vous devriez regarder les techniques vaut mieux pour vous problème.

Si votre programme utilise quelques objets différents, et ne pas ajouter de nouvelles classes, de son mieux de rester avec énumérations.

Mais si vous programme utilise beaucoup de différents objets (classes différentes), et peut-être ajouter de nouvelles classes, à l'avenir, mieux essayer la voie de l'héritage.

scroll top