2012-09-22 4 views
5

정말 비슷한 방법을 사용하는 두 개의 객체가 한 줄에 저장됩니다. 예를 들어 :Java의 추상 클래스에서 새 객체 만들기

public class Cat extends Animal 
public class Dog extends Animal 

그리고 그들은 모두 추상 클래스 Animal에서 breed 방법을 사용합니다. 하나는 new Dog()이고 다른 하나는 new Cat()입니다. 지금 막 동물에서 abstract public void breed();으로 선언해야하지만 일반화 할 수있는 방법이 있으므로 재정의 할 추상 메소드를 만들 필요가 없습니다.

+0

예는, 클래스의 모든 메소드가 –

+1

@SashiKant 추상적해야 할 필요는 없다 그러나 그것은'InstantiationException'을 던졌습니다. –

답변

3

breed으로 "나를 만든 자녀"라고 가정 할 때 여러 가지 방법이 있습니다.

반사

먼저 반사를 사용하는 것입니다. 당신이 당신의 클래스에 대한 인자없는 생성자가있는 경우,이 Class.newInstance를 호출하는 것만 큼 쉽습니다 : 당신이 모든 서브 클래스에서 인자없는 생성자가없는 경우

public Animal breed() { 
    try { 
     return (Animal) getClass().newInstance(); 
    } catch (Exception ex) { 
     // TODO Log me 
     return null; 
    } 
} 

, 당신은이해야합니다 모든 하위 클래스 전반에 걸쳐 균일 한 생성자. 당신이 Cat(int, String)Dog(int, String)이있는 경우 예를 들어, 당신은 Class.getConstructor를 통해 생성자를받을 수 있도록에 newInstance를 호출해야합니다

return (Animal) getClass().getConstructor(int.class, String.class).newInstance(0, "Unnamed"); 

int 여기 String 예를 들어 나이와 이름 일 수있다. 리플렉션을 통해이를 수행하는 방법입니다. 그런 다음 추상 클래스는 생성자에서이 인스턴스을 가지고

public interface Provider<T> { 
    T create(); 
} 

:

공급자

또 다른 방법이 간단한 인터페이스를 사용하는 것입니다

public abstract class Animal { 
    private final Provider<Animal> animalProvider; 

    protected Animal(... , Provider<Animal> animalProvider) { 
     // ... 
     this.animalProvider = animalProvider; 
    } 

    public Animal breed() { 
     return animalProvider.create(); 
    } 
} 

그런 다음 서브 클래스는 서브 클래스의 새로운 인스턴스를 생성하는 수퍼 클래스에 Provider<Animal>을 전달합니다 :

public class Dog extends Animal { 
    public Dog(...) { 
     super(... , new DogProvider()); 
     // ... 
    } 

    private static class DogProvider implements Provider<Animal> { 
     public Animal create() { 
      return new Dog(...); 
     } 
    } 
} 

다른 하위 클래스도 마찬가지입니다.

참고 :breed에 의해 "나를 입력하십시오"라는 뜻인 경우 질문을 수정해야합니다. 나는 데이터 컨테이너 방법에 대한 get/set 표기 규칙에 따라 권장

public abstract class Animal { 
    protected final Breed breed; 

    protected Animal(... , Breed breed) { 
     // ... 
     this.breed = breed; 
    } 

    public Breed getBreed() { 
     return breed; 
    } 
} 

: 이것은 당신이 무엇을 의미하는지 경우, 다음이 가능한 솔루션입니다. Java는 이러한 명명 규칙을 처리하도록 설계된 bean 클래스를 가지고 있으며, 많은 플랫폼에서 어느 정도 표준입니다. 당신의 서브 클래스 :

public class Dog extends Animal { 
    public Dog(...) { 
     super(... , new Breed(...)); 
     // ... 
    } 
} 
2

아니요. 당신은 당신이 당신의 추상 클래스에

public abstract Breed getBreed(); 

다음 각 하위 클래스에서

public Breed getBreed() { 
    return new DogBreed(); 
} 

이 있고이 할 생각

아래와 같이 한 일을 뭔가를해야 할 것이다 비슷한 고양이 돌아 오는 고양이.

또는

breed라는 Animal 클래스의 보호 된 필드가 있어야합니다. 이것은 각 서브 클래스에서 초기화 될 수 있습니다. 이것은 추상 메소드의 필요성을 제거합니다. 예를

public abstract class Animal { 
    Breed breed; 
... 
} 

를 들어 다음 개에

public class Dog extends Animal { 
    public Dog() { 
     breed = new DogBreed(); 
    } 
} 

이 고양이 비슷한 있습니다. 또한 개/고양이의 ctor의 품종을 전달하는 동안 오히려 개

의 한 품종에 모델을 제한하는 것보다 다른 품종의 개 개체를 만들 수 있도록

그것은 당신이 가치가있을 수도 있습니다 나는 확실하지 않다 번식은 반드시 당신의 모범에서 정확하게 모델링됩니다. 새 개가 품종이되기를 정말로 원하십니까? 아니면 타입을 의미합니까? 어떤 경우에는 그것은 단지 동물이며, 추상적 인 방법으로 동물을 돌려 보내는 것은 길입니다.

3

사실, 가능합니다. 당신은 성능이 약간 불확실이 될 수 있도록 반사를 사용할 필요가 있지만,이 (테스트되지 않은) 작업을해야합니다

public abstract class Animal{ 
    public Animal breed(){ 
     return getClass().newInstance(); 
    } 
    //other methods 
} 

이 실제 호출 형식의 새 인스턴스를 반환합니다 (이 구현 된 것) 동물의하지 유형 .

실제로 이것은 Prototype Pattern과 다소 비슷합니다. 이 경우 기존 인스턴스를 복사하지 않고 새 인스턴스를 생성합니다.

편집 @FrankPavageau이 코멘트에 지적 오히려 생성자에서 예외를 마스킹보다, 당신이 던져 예외를 래핑합니다 어느

public abstract class Animal{ 
    public Animal breed(){ 
     return getClass().getConstructor().newInstance(); 
    } 
    //other methods 
} 

를 사용하여 동일한 결과를 얻을 수 있듯이

InvocationTargetException에서 좀 더 깔끔하고 쉽게 디버깅하기 쉽습니다. 그 제안에 대해 @FrankPavageau에게 감사드립니다.

+0

이를 시도 ... 사실, 나는 그 영업 묻는 무슨 생각하지 않지만 –

+0

@ Eng.Fouad 그것을 던지거나 그것을 잡을 필요가 있다고 말 했나요? 이 문제를 웹에서 해결할 수있는 사례가 많이 있습니다. –

+0

네,'InstantiationException'을 던집니다. 직접 시험해 볼 수도 있습니다. –

관련 문제