2010-07-02 2 views
54

저는 추상 메소드를 정의하는 추상 클래스 A를 가지고 있습니다. 이것은 클래스가 인스턴스화 될 수 있으려면 모든 추상 메소드가 구현되어야 함을 의미합니다.어떻게 생성자를 abstract 클래스의 모든 서브 클래스에 강제적으로 정의 할 수 있습니까?

모든 하위 클래스에서 매개 변수로 2 개의 int를 사용하여 생성자를 구현하고 싶습니다.

생성자 선언은 하위 클래스에 정의 된 생성자를 원하며 구현에 대해 알지 못하기 때문에 내 용도를 무효화합니다. 게다가 나는 추상적 인 것으로 생성자를 선언 할 수 없다.

이 방법이 있습니까? 내가 원하는 것을

예 :

수 있습니다 내가 Matrix 클래스의 API를 정의하고 있다고 말한다. 내 문제는 매트릭스가 차원을 바꿀 수 없다는 것입니다.

매트릭스를 만들려면 그 크기를 제공해야합니다.

따라서 모든 구현 자들이 생성자에게 크기를 매개 변수로 제공하기를 원합니다. 이 생성자는 구현 문제가 아니라 문제에 의해 동기 부여됩니다. 구현은 메소드의 모든 의미가 유지된다면 원하는대로 할 수 있습니다.

내 추상 클래스에서 invert() 메소드의 기본 구현을 제공하고자한다고 가정 해 보겠습니다. 이 메서드는 반전 된 치수가 this 인 새 행렬을 만듭니다. 보다 구체적으로는, abstract 클래스에서 정의되고있는 것처럼, 2 개의 int를 취하는 생성자를 사용해, 같은 클래스의 새로운 인스턴스를 작성합니다 (this). 인스턴스를 알지 못하기 때문에 리플렉션 (getDefinedConstructor)을 사용할 것이고 나는 그것을 얻고 구현을위한 의미있는 것이라고 waranty에게 원한다.

+0

우아한 해결책은 다음에서 찾을 수 있습니다. http://stackoverflow.com/questions/6028526/java-force-an-extending-class –

답변

48

하위 클래스에서 생성자의 특정 서명을 강요 할 수는 없지만 이 두 개의 정수를 취하는 추상 클래스의 생성자를 통과하도록 할 수 있습니다. 서브 클래스은 매개 변수없는 생성자에서 해당 생성자를 호출하여 상수를 전달할 수 있습니다. 그것은 당신이 올 수있는 가장 가까운 것입니다.

또한 여러분은 구현에 대해 알지 못합니다. 그래서 두 개의 정수가 필요한 생성자를 갖는 것이 적절한 지 어떻게 알 수 있습니까? 그들 중 하나가 문자열을 필요로한다면 어떨까요? 또는 아마도 정수 중 하나에 상수를 사용하는 것이 좋습니다.

여기서 큰 그림은 무엇입니까? 왜 특정 하위 생성자 서명을 강제로 적용 하시겠습니까? (내가 말할 때, 당신은 실제로 이 작업을 수행 할 수 있지만, 당신이 그것을 원하는 이유를 설명 할 경우, 솔루션 자체가 야기 될 수 있습니다.)

하나의 옵션은 공장에 대해 별도의 인터페이스를 가지고있다 :

interface MyClassFactory 
{ 
    MyClass newInstance(int x, int y); 
} 

각각의 구체적인 서브 클래스 MyClass에는 두 개의 정수가 주어진 인스턴스를 작성하는 방법을 알고있는 팩토리가 필요합니다. 그것은 대단히 편리하지 않습니다 - 그리고 당신은 여전히 ​​공장의 인스턴스를 구축해야합니다. 다시, 여기 실제 상황은 무엇입니까?

+2

Matrix 클래스의 API를 정의한다고 가정 해 보겠습니다. 내 문제는 매트릭스가 차원을 바꿀 수 없다는 것입니다. 매트릭스를 만들려면 크기를 입력해야합니다. 따라서 모든 구현자는 생성자에게 크기를 매개 변수로 제공해야합니다. 이 생성자는 구현 문제가 아니라 문제에 의해 동기 부여됩니다. 구현은 메소드의 모든 의미가 유지된다면 원하는대로 할 수 있습니다. – dodecaplex

+0

@dodecaplex : 그러나 항상 * 10 * 10 인 FixedSizeMatrix 구현체를 만들고 싶다면 어떻게해야합니까? 어쨌든 * 생성자를 다형 적으로 호출 할 수는 없으므로 구현을 제한하려는 이유는 무엇입니까? –

+1

그렇다면 구현은 내 API를 따르지 않을 것입니다 ... 그럴만 한 이유가 있다면 0 인수 생성자와 args가 10x10이 아닌 경우 예외를 발생시키는 2 인수 생성자를 제공합니다. 이것은 동일한 구현 및 동일한 크기의 빈 Matrix를 여전히 만들 수 있음을 의미합니다 (효과적인 구현을 알지 못함). 그러나이 구현을 10x10이 아닌 Matrixes에 사용하려고하면 예외가 발생합니다 . – dodecaplex

2

구현 클래스가 사용할 내부 표현을 인터페이스에 정의해야하는 경우 잘못 처리하는 경우입니다. encapsulationdata abstraction에 대해 읽으십시오.

추상 구현이 특정 구현 세부 정보를 사용하는 경우 해당 추상 클래스에 속합니다. 즉, 추상 클래스는 추상화 된 메소드가 작동하는 데 필요한 내부 상태를 초기화 할 수있는 생성자를 정의해야합니다.

일반적으로 생성자는 해당 객체 인스턴스의 초기 상태에 대한 세부 정보를 제공하여 클래스의 인스턴스를 작성합니다. 그렇다고해서 대부분의 소프트웨어에서 보듯이 생성되는 인스턴스가 각 개별 인수에 대한 참조를 복사해야한다는 것을 의미하지는 않습니다. 따라서 Java가 하위 클래스에 특정 생성자 시그니처의 구현을 강제로 제공하는 구조를 제공하더라도 해당 하위 클래스는 인수를 쉽게 폐기 할 수 있습니다.

+1

글쎄, n 차원 공간에서 Point를 정의한다면, 그 점이 m 차원 공간 (m! = n)에 존재할 수 없다는 것을 확실히 알고 있습니다. 그러므로 공간의 차원은 점 구현에 관계없이 Point의 고유 속성입니다. 내가 알 수있는 한 이것은 캡슐화와 데이터 추상화입니다. 만들려는 각 인스턴스에 대해 차원을 지정해야하는 경우 모든 구현에서이 인수를 사용하는 생성자를 제공해야한다는 것이 자연 스럽습니다. – dodecaplex

+0

@dodecaplex, 아, 좋은 예입니다. 여러분이 2 차원 점에 대해 이야기하고 있다고 가정 해 봅시다. 물론 x와 y 값을 사용하여 표현할 수 있습니다. 또는 라디안 /도 값과 거리 값을 사용하여 표현할 수 있습니다. 한 가지 예. 다른 방법이있을 수 있습니다. 당신은 단지 당신이 구현할 수있는 방법을 안다고 생각합니다. 어쨌든, 정의에 따라 표현을 시행하려는 경우 데이터 추상화를 사용하지 않습니다. –

3

다음과 같이 시도해 볼 수 있습니다. 구현 클래스에 적절한 인수가있는 생성자가없는 경우 생성자가 예외를 throw합니다.

이것은 바보입니다. OK와 나쁜 비교. OK가 요구 사항을 충족시키고 런타임 검사를 통과한다는 점을 제외하면 두 클래스 모두 동일합니다. 따라서 요구 사항을 시행하면 비생산적인 바쁜 업무가 촉진됩니다.

더 좋은 해결책은 일종의 공장입니다.

abstract class RequiresConstructor 
{ 
    RequiresConstructor(int x, int y) throws NoSuchMethodException 
    { 
    super(); 
    System.out.println(this.getClass().getName()) ; 
    this.getClass(). getConstructor (int.class , int.class) ; 
    } 

    public static void main(String[] args) throws NoSuchMethodException 
    { 
    Good good = new Good (0, 0); 
    OK ok = new OK(); 
    Bad bad = new Bad(); 
    } 
} 

class Good extends RequiresConstructor 
{ 
    public Good(int x, int y) throws NoSuchMethodException 
    { 
    super(x, y) ; 
    } 
} 

class OK extends RequiresConstructor 
{ 
    public OK(int x, int y) throws NoSuchMethodException 
    { 
    super(x, y) ; 
    throw new NoSuchMethodException() ; 
    } 

    public OK() throws NoSuchMethodException 
    { 
    super(0, 0) ; 
    } 
} 

class Bad extends RequiresConstructor 
{ 
    public Bad() throws NoSuchMethodException 
    { 
    super(0, 0) ; 
    } 
} 
0

추상 클래스에는 매개 변수에 대해 취할 수있는 추상 메서드가 있어야합니다. 예를 들어 :

public abstract void setSize(int rows,int columns); 
2

조금 늦었지만 ...

그냥 항상 슈퍼 생성자 호출되는 클래스의 기본 생성자를 만듭니다. 이 기본 생성자에서는 정의 된 모든 생성자를 자신의 클래스 객체 (추상 수퍼 클래스가 아니라 구체적인 하위 클래스)로 반사하여 검사 할 수 있습니다. 구현하려는 생성자가 누락 된 경우 런타임 예외가 발생합니다.

import java.lang.reflect.Constructor; 

public abstract class Gaga { 
    public Gaga() { 
    boolean found = false; 
    try { 
     Constructor<?>[] constructors = getClass().getConstructors(); 
     for (Constructor<?> c : constructors) { 
     if (c.getParameterTypes().length==2) { 
      Class<?> class0 = c.getParameterTypes()[0]; 
      Class<?> class1 = c.getParameterTypes()[1]; 
      if ((class0.getName().equals("int") || class0.isAssignableFrom(Integer.class)) 
       && (class1.getName().equals("int") || class1.isAssignableFrom(Integer.class))) 
      found = true; 
     } 
     } 
    } catch (SecurityException e) 
    { 
     found = false; 
    } 

    if (!found) 
     throw new RuntimeException("Each subclass of Gaga has to implement a constructor with two integers as parameter."); 

    //... 
    } 

} 

:

가 다시 문을 통해 해킹의 맛을 가지고 있기 때문에 나는 반성의 좋은 친구가 아니지만, 가끔은 도움이 ...

이 예에서보세요 그리고 테스트 클래스 : Gaga1의 객체가 생성 될 주요 기능에

public class Test { 
    private class Gaga1 extends Gaga { 
    public Gaga1() { this(0, 0); } 
    public Gaga1(int x, Integer y) { } 
    } 

    private class Gaga2 extends Gaga { 

    } 

    public static void main(String[] args) 
    { 
    new Gaga1(); 
    new Gaga1(1, 5); 
    new Gaga2(); 
    System.exit(0); 
    } 
} 

하지만 Gaga2의 창조는 런타임 예외가 발생합니다.

하지만이 생성자가 호출되었는지 확신 할 수 없습니다. 원하는 작업을 수행하는지 확인할 수 없습니다.

이 테스트는 리플렉션 작업을하는 경우에만 유용합니다.

관련 문제