Je travaille avec une hiérarchie de type smallish, quelque chose comme ce qui suit, et disons qu'il n'y aura jamais d'autres types d'animaux dans mon triste monde sans safari (I suis pas du tout inquiet de la résistance à l'expansion):Écrire une API générique pour un type 'famille'
public abstract class Animal {};
public sealed class Dog : Animal {};
public sealed class Cat : Animal {};
public sealed class Turtle : Animal {};
public sealed class Bird : Animal {};
J'aimerais traiter tous les animaux de la même aussi loin que l'API est concerné, mais il est évident qu'ils répondent un peu différemment dans les situations ci-dessous :
public class AnimalCare {
public void Feed<T> (T pet) where T: Animal;
public T PickUp<T> (PetStore store);
}
À première vue l'idée d'effectuer des tétées sans mettre un nourrir moi thod sur la classe des animaux (désolé, je sais que l'exemple est d'atteindre à ce stade, mais prétendons pour l'argument que AnimalCare est la vue de mes modèles animaux et je suis assez catégorique sur la séparation des préoccupations) suggérerait un visiteur . Mais ce que je voudrais vraiment faire est de laisser ci-dessus est la seule sorte de consommateurs API de besoin AnimalCare à se soucier, alors que je fais quelque chose comme ce qui suit:
public class AnimalCare {
public void Feed<T> (T pet) where T : Animal;
public T PickUp<T> (PetStore store);
public void Feed<Dog> (Dog rover)
{
// dump out alpo, lift toilet seat
}
public void Feed<Turtle> (Turtle franklin)
{
// do turtles eat? let him figure it out himself.
} // ...etc.
public Dog PickUp<Dog> (PetStore store)
{
// get bone, tennis ball, leash
}
public Bird PickUp<Bird> (PetStore store)
{
// make sure not dead, nailed to perch
} // ...etc.
}
Et ainsi de suite. Je sais que la première partie (les méthodes Feed()) est bien de surcharger sans même avoir besoin de génériques, mais ça me laisse toujours une implémentation maladroite pour PickUp (puisque ce n'est pas légal à implémenter comme je l'ai esquissé ci-dessus), misérable comme PickUpDog // PickUpBird etc Je voudrais vraiment éviter d'avoir une "vue" distincte pour les consommateurs d'AnimalCare et ses amis partageant les mêmes idées d'avoir à se préoccuper de.
J'ai joué avec des classes spécialisées imbriquées et d'autres tentatives bizarres de refactorisation de composition ou d'interface, mais je n'arrive pas à faire les choses correctement et je suis coincé. Y a-t-il une façon propre de faire quelque chose comme ce que je veux, ou suis-je résigné à implémenter un AnimalCare pour chaque Animal concret?
EDIT
points de Joel à propos de l'usine/dépôt m'a fait penser un peu plus. Appelons plutôt les méthodes d'intérêt un peu plus raisonnable:
public class AnimalPresentation {
public void Show (Dog dog);
public void Show (Cat cat);
//..etc.
public Animal Get (PetStore store);
}
Cela aurait fait plus de sens en premier lieu je suppose. Le type d'animal à sortir de PetStore n'est pas connu au moment où Get est appelé, mais dans l'implémentation générale de Get, une fois le type déterminé, il se branche sur la surcharge spécifique. Est-ce que les sous-types spécifiques de PetStore sont la meilleure/seule façon d'avancer ici?
C'est ce dont j'avais peur. Exemple ridicule mis à part, je ne veux pas que la classe Animal ait à connaître les exigences de présentation ou de formatage de AnimalCare et d'autres classes. Tout ce dont j'ai besoin fait partie de l'API publique et j'espérais vraiment avoir un moyen d'avoir les implémentations concrètes dans la classe AnimalCare. –
Vérifier mes modifications. L'implémentation concrète dans AnimalCare peut être en incorporant les classes qui héritent de IAnimalCareClient dans votre classe AnimalCare. –