Я работаю с небольшой иерархией типов, что-то вроде следующего, и допустим, что в моем печальном мире без сафари никогда не будет других типов животных (меня совсем не беспокоит устойчивость к расширению ):
public abstract class Animal {};
public sealed class Dog : Animal {};
public sealed class Cat : Animal {};
public sealed class Turtle : Animal {};
public sealed class Bird : Animal {};
Я хотел бы относиться ко всем животным одинаково в том, что касается API, но, очевидно, они реагируют немного по-другому в следующих ситуациях:
public class AnimalCare {
public void Feed<T> (T pet) where T: Animal;
public T PickUp<T> (PetStore store);
}
На первый взгляд, идея выполнения кормления без использования метода подачи в классе Animal (извините, я знаю, что пример подходит к этому моменту, но давайте притворяться, что аргумент в пользу AnimalCare - это представление моих моделей Animal). и я довольно непреклонен в разделении проблем) предложил бы посетителю. Но то, что я действительно хотел бы сделать, это позволить приведенному выше быть единственным видом API, о котором нужно беспокоиться потребителям AnimalCare, в то время как я делаю что-то вроде следующего:
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.
}
И так далее. Я знаю, что первую часть (методы Feed ()) можно просто перегрузить, даже не требуя обобщений, но это все еще оставляет меня с неловкой реализацией для PickUp (так как ее нелегально реализовать, как я нарисовал выше), что-то такие жалкие, как PickUpDog // PickUpBird и т. д. Мне бы очень хотелось, чтобы у потребителей AnimalCare и его друзей-единомышленников не было отдельного «представления» о том, о чем следует беспокоиться.
Я играл с вложенными специализированными классами и другими странными попытками реорганизации композиции или интерфейса, но я не могу понять, что это правильно, и я застрял. Есть ли чистый способ сделать что-то наподобие того, что я хочу, или я смирился с внедрением AnimalCare для каждого конкретного Animal?
EDIT
Точка зрения Джоэла о фабрике / хранилище заставила меня задуматься. Давайте вместо этого назовем интересующие нас методы более разумными:
public class AnimalPresentation {
public void Show (Dog dog);
public void Show (Cat cat);
//..etc.
public Animal Get (PetStore store);
}
Это было бы более разумно, во-первых, я полагаю. Тип Animal, который нужно получить из PetStore, неизвестен во время вызова Get, но в общей реализации Get, когда тип определен, он переходит к определенной перегрузке. Являются ли определенные подтипы PetStore лучшим / единственным способом продвижения вперед?