Programing

추상 클래스의 모든 하위 클래스에서 생성자를 강제로 정의하려면 어떻게해야합니까?

lottogame 2020. 11. 22. 18:53
반응형

추상 클래스의 모든 하위 클래스에서 생성자를 강제로 정의하려면 어떻게해야합니까?


추상 메서드를 정의하는 추상 클래스 A가 있습니다. 즉, 클래스를 인스턴스화 할 수 있으려면 모든 추상 메서드를 구현해야합니다.

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

생성자를 선언하면 내 목적이 실패합니다. 생성자를 서브 클래스에 정의하고 싶고 구현에 대해 아무것도 모르기 때문입니다. 또한 생성자를 추상적 인 것으로 선언 할 수 없습니다.

이 작업을 수행하는 방법이 있습니까?

내가 원하는 것의 예 :

내가 Matrix 클래스의 API를 정의하고 있다고 가정 해 봅시다. 내 문제에서 Matrix는 치수를 변경할 수 없습니다.

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

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

invert()내 추상 클래스에서 메서드 의 기본 구현을 제공하고 싶다고 가정 해 보겠습니다 . 이 방법은 this역 차원 으로 새 행렬을 만듭니다 . 보다 구체적으로, 추상 클래스에 정의되어 있으므로 this두 개의 int를 취하는 생성자를 사용하여 와 동일한 클래스의 새 인스턴스를 만듭니다 . 인스턴스를 알지 못하기 때문에 리플렉션 (getDefinedConstructor)을 사용하고 구현에 의미가 있음을 보증하는 방법을 원합니다.


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

더욱이, 당신이 말했듯이, 당신은 구현에 대해 아무것도 모릅니다. 그래서 두 개의 정수를 필요로하는 생성자를 갖는 것이 적절하다는 것을 어떻게 알 수 있습니까? 그들 중 하나도 문자열을 필요로한다면? 또는 해당 정수 중 하나에 상수를 사용하는 것이 합리적 일 수 있습니다.

여기서 더 큰 그림은 무엇입니까- 하위 클래스에 특정 생성자 서명을 강제하고 싶습니까? (내가 말할 때, 당신은 실제로 수 없습니다 당신은 당신이 그것을 원하는 이유, 솔루션 자체가 야기 될 수 있습니다 설명하면이 있지만.)

한 가지 옵션은 공장에 대해 별도의 인터페이스를 갖는 것입니다.

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

그런 다음 각각의 구체적인 하위 클래스에는 MyClass두 개의 정수가 주어지면 인스턴스를 빌드하는 방법을 알고있는 팩토리가 필요합니다. 하지만 매우 편리하지는 않습니다. 공장 자체의 인스턴스를 구축해야합니다. 다시, 여기서 실제 상황은 무엇입니까?


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

이것은 어리석은 일입니다. OK와 Bad를 비교하십시오. 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 ) ;
    }
}

인터페이스에서 구현하는 클래스가 사용할 내부 표현을 정의해야한다면 잘못하고있는 것입니다. 캡슐화데이터 추상화 에 대해 읽어보십시오 .

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

Generally, constructors are intended to create an instance of a class by providing some details of the initial state of that object instance. This does not mean that the instance being constructed should copy a reference to each individual argument as is often the case in most software I see. Therefore, even if Java did offer a construct for forcing the implementation of certain Constructor signatures on subclasses, those subclasses could easily discard the arguments.


A little bit late, but...

Just create a default constructor in your class which is always called as super constructor. In this default constructor you can check all defined constructors with reflection on it's own class object (which is then not the abstract super class but the concrete subclass). If the constructor you want to be implemented is missing, throw a runtime exception.

I'm not a great friend of reflection because it has the taste of hacking through the back door, but sometimes it helps...

Have a look at this example:

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.");

    //...
  }

}

And a test class:

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

In the main function the objects of Gaga1 will be created, but the creation of Gaga2 will throw a runtime exception.

But you can't be sure that this constructor is called - you can't even ensure that it is doing the things you want.

This test is only useful if you're working with reflection.


Have the abstract class have an abstract method which takes what you would have for parameters. For instance:

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

참고URL : https://stackoverflow.com/questions/3164334/how-can-i-force-a-constructor-to-be-defined-in-all-subclass-of-my-abstract-class

반응형