2010-01-18 9 views
0

저는 다음과 같은 작은 유형 계층 구조로 작업하고 있으며 슬픈 사파리가없는 다른 세상에서 다른 동물 유형이 존재하지 않는다고 말합니다'family'유형에 대한 일반 API 작성하기

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); 
} 

처음에는 피드를 넣지 않고 피드를 수행한다는 생각을 푸십시오. (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. 
} 

등등 : 나는 다음과 같은 일을하면서하지만 제가 정말하고 싶은 것은, 위의 걱정하는 AnimalCare 필요의 API 소비자의 유일한 종류의하자입니다. 제 1 부분 (Feed() 메소드)은 제네릭을 필요로하지 않고 그냥 오버로드하는 것이 좋지만 픽업 (Pickup)에 대한 어색한 구현은 여전히 ​​남아 있습니다 (위의 스케치와 같이 구현할 수 없기 때문에). PickUpDog // PickUpBird 등의 비참한 것입니다. 저는 AnimalCare의 소비자와 그와 비슷한 생각을 가진 친구들이 걱정해야 할 별도의 "보기"를 피하고 싶습니다.

저는 컴포지션 또는 인터페이스 리팩토링에서 특수 클래스 및 기타 기괴한 시도를 중첩시켜 놀았지만 올바르게 만들 수없는 것 같아 막혔습니다. 내가 원하는 것과 같은 것을 할 수있는 깨끗한 방법이 있습니까? 아니면 각 구체적인 동물에 대한 AnimalCare 구현을 사퇴 했습니까? 공장/저장소에 대한

편집

조엘의 요점은 내가 좀 더 생각했다. 대신에 관심있는 방법을 조금 더 합리적이라고 부르 자.

public class AnimalPresentation { 
    public void Show (Dog dog); 
    public void Show (Cat cat); 
    //..etc. 
    public Animal Get (PetStore store); 
} 

내가 처음에 생각한 것보다 더 의미가 있었을 것이다. PetStore에서 나올 Animal 유형은 Get이 호출 될 때 알 수 없지만 Get의 일반 구현에서 일단 유형이 결정되면 특정 과부하로 분기됩니다. PetStore의 특정 하위 유형이 최선의 방법일까요? 거기에 당신의 동물이 인터페이스 IAnimal

첫째 :

답변

1

내가 AnimalCare의 문제는 그것이 Animal 저장소에 Animal 인스턴스에 대한 공장, 또는 적어도 접근이 본질적 것을 생각 : 다음과 같은 간단한 일이됩니다 . 따라서 PickUp 함수는 특정 유형 대신 Animal 객체를 반환해야합니다.

또는 AnimalCare을 특정 유형 (AnimalCare<T>)으로 지정할 수 있습니까? 이 예제는 실제 의도와 관련해서는 측정하기가 거의 어렵 기 때문에 이러한 아이디어가 타격을 입지 않으면 사과드립니다.

1

편집
이 같은 것을 고려해 볼 수 있습니다. 그들은 어떤 방법을 알지 못합니다. 그런 다음 클라이언트는 다음 몇 가지 목록에 보관해야합니다

class DogClient : IAnimalCareClient<Dog> 
{ 
    void Init(Dog animal) { //bla } 
    void Feed() {} 
    Dog Pickup(PetStore store) { //bla again } 
} 

처럼 모든 동물 유형의 클라이언트를 만들

같은 새로운 인터페이스를 생성하고, 유형 등 다양한 DLL의에있을 수 있습니다 당신은 단지 참조를 얻을 필요가있다.

은 그럼 그냥

class AnimalCare 
{ 
    void Feed<T>(T animal) 
    { 
     //GrabWorkerFromStack<T>() should return the type IAnimalCareClient<T> 
     IAnimalCareClient<T> worker = Activator.CreateInstance(GrabWorkerFromStack<T>()); 
     worker.Init(animal); 
     worker.Feed(); 
    } 
} 

원래의 대답
은 기본적으로 당신은 모든 동물에 대한 모든 속성을 구현하기 위해 AnimalCare 클래스를 강제 할 수 없기 때문에, 동물 자체에서 책임을 마련하고자합니다.

interface IAnimal 
{ 
    void Feed(); 
    IAnimal Pickup(PetStore store); 
} 

class Dog : IAnimal 
{ 
    void Feed() { /* feed */ } 
    IAnimal Pickup(PetStore store) { /* grab animal and return */ } 
} 

class AnimalCare 
{ 
    void Feed(IAnimal animal) 
    { 
     animal.Feed(); 
    } 

    T Pickup<T>(T animal, PetStore store) where T: IAnimal 
    { 
     return (T)animal.Pickup(store); 
    } 
} 
+0

그건 내가 두려워했던거야. 말도 안되는 예제 외에, AnimalCare 클래스 및 다른 클래스의 프레젠테이션 또는 서식 지정 요구 사항에 대한 지식을 Animal 클래스에 제공하지 않아야합니다. 필요한 모든 것은 공개 API의 일부이며 실제로 AnimalCare 클래스에서 구체적인 구현 방법을 찾고있었습니다. –

+0

내 편집을 확인하십시오. AnimalCare에서의 구체적인 구현은 AnimalCare 클래스에 IAnimalCareClient 을 상속받은 클래스를 임베드하여 수행 할 수 있습니다. –

0

인터페이스를 사용할 수 있지만 어떤 특정 요구 사항이 있는지 모르겠지만 동물이 다른 동물과 공유 할 수 있지만 인터페이스가 필요없는 특성이 좋은 시작일 수 있습니다. 예를 들어

:

interface IFeedable 
{ 
    void Feed(); 
} 

interface IMammal<TChild> 
    where TChild: IMammal<TChild> 
{ 
    IEnumerable<TChild> Reproduce(); 
} 

class Dog: IFeedable, IMammal<Puppy> 
{ 
    // ... 
} 

나는 이것이 정상적인 상속이 가장 좋은 방법하지 않을 수 있었다으로 특히 경우, 인터페이스 모든 시간 (아마 그들을 남용)를 사용합니다.

관련 문제