어떤 OO 언어가 재정의 된 메소드가 기본을 호출하도록 보장하는 메커니즘을 지원합니까?


12

이 기능은 유용한 언어 기능 일 수 있으며 이미 지원하는 언어가 있는지 궁금합니다.

아이디어는 다음과 같은 경우입니다.

class C
  virtual F
     statement1
     statement2

class D inherits C
  override F
     statement1
     statement2
     C.F()

CF ()에 적용되는 키워드가있을 것입니다. 위 코드의 마지막 줄을 제거하면 "이 메소드는 재정의 될 수 있지만 여기서 구현은 실행해야합니다"라는 말 때문에 컴파일러 오류가 발생합니다.


답변:


14

예, 그렇습니다. 그것은 OO의 스칸디나비아 모델이라고 불리며, 예를 들어 Simula에서 사용됩니다 (현재 널리 보급되어 찍은 다른 OO 모델은 미국 모델입니다). 스칸디나비아 모델에서는 재정의하지 않고 하위 동작을 제공합니다.

슈퍼 클래스의 메소드 foo에서 :

some-code-before
INNER // this is the actual Simula keyword
some-code-after

서브 클래스의 메소드 foo에서 :

some-code-in-subclass

수퍼 클래스 인스턴스의 메소드 foo를 호출하면 발생 some-code-before하고 아무 일도하지 않지만 서브 클래스의 인스턴스 foo를 호출하면 , 그리고 .some-code-afterINNERsome-code-beforesome-code-in-subclasssome-code-after


9

내가 아는 언어는 재정의 된 메소드를 호출하지 않습니다. 실제로 일부 언어에서는 재정의 할 수없는 메서드 ( newC # 에서 키워드 사용)를 재정의 할 수 있습니다. 그러나 여기에는 두 가지 방법이 있습니다.

첫 번째는 클래스 외부에서 호출 할 수없는 재정의 가능한 메서드 (예 : C #, Java 또는 C ++) 를 호출하는 재정의 할 수없는 메서드 (예 : virtualC #에 키워드 가없는 키워드 또는 finalJava에 키워드 가있는 메서드)를 만드는 것입니다 protected.

class C
  A
     statement1
     F
     statement3

  protected virtual F
     statement2

class D inherits C

  protected override F
     statement4
     C.F()

재정의 C하는 클래스 는 자유롭게 동작을 재정의 F하고 동작을 수정할 수 있지만 클래스 외부에서 온 호출자는 클래스를 통해서만 액세스 할 수 A있습니다.

편집 : 다른 사람들이 지적했듯이 이것을 템플릿 메소드 패턴 이라고합니다 .

두 번째 방법은 기본 클래스에 지정된 전제 조건과 사후 조건 (예 : Eiffel 또는 Code Contracts with C #)을 적용하는 언어를 사용하는 것입니다. 기본 클래스를 강제로 호출하지는 않지만 재정의 된 메소드가 동일한 명령문을 수행하도록 강제 할 수 있습니다. 언어를 사용하여 측면을 상속 할 수있는 경우 측면을 사용하면 도움이 될 수 있습니다.


2
privateC ++에서 메소드를 재정의 할 수도 있습니다 :) Herb Sutter가 여기 에 자세히 설명합니다.
fredoverflow

템플릿 패턴에는 상속 계층 구조를 자세히 살펴보면서 매번 다시 구현해야하는 단점이 있습니다. Simula를 사용한 예제는 더 우아하고 여전히 템플릿 패턴을 허용합니다.
Pavel Voronin

7

실제로 언어의 일부는 아니지만 Java 용 FindBugs 정적 코드 분석기 OverrideMustInvoke에는 개발자가 메소드에 추가 할 수 있는 주석 이 있으며, 이는 슈퍼 구현을 호출하지 않는 대체 메소드를 찾으면 FindBugs가 오류를 표시하게합니다. . 재정의 메소드에서 호출이 첫 번째인지 마지막인지를 지정할 수도 있습니다.


6

수퍼 클래스 메소드를 호출해야하는 것은 안티 패턴 입니다. 컴파일 타임에 적용되지 않으면 오류가 발생하기 쉬우므로이를 확인하는 언어 구성을 찾고 있습니다.

모든 OO 언어에서 지원되는 방법이 있습니다 : 템플리트 메소드 패턴 . 여기서는 슈퍼 클래스 메서드를 재정의 할 수 없도록 만들고 재정의 가능한 메서드를 호출합니다. 그런 다음 서브 클래스는이 메소드를 대체하여 기능을 추가 할 수 있습니다.

class super {
  public final void doSomething() {
    doSpecialthing();
    doMore();
  }
  public void doSpecialthing() {
  }
}

재정의 된 메소드에 대한 호출 위치에 따라 실행 순서를 결정할 수 있습니다. 일반 슈퍼 호출을 사용하면 하위 클래스 구현자가 원하는 순서입니다.


1

내가 생각할 수있는 가장 가까운 패턴은 자체 구독 이벤트입니다. 약간 번거롭고 전혀 직관적이지 않지만 목표를 달성합니다.

class C
{
    public void F()
    {
        ...
        OnF()
    }

    protected event OnF
}

class D : C
{
    public D()
    {
        base.OnF += this.F
    }

    private void F
    {
        ...
    }
}

1
이것은 매우 일반적인 디자인 패턴이며 때로는 프로 및 포스트 재정의가 모두 적용됩니다. ViewWillAppear (), ViewDidAppear (). 서브 클래스가 기본 동작을 수정하지 않고 확장하도록 허용하려는 경우에 이상적입니다.
Kris Van Bael

1

리스프 머신 "flavors"는 "before" "after"및 "around"유형의 메소드를 상속 된 기본 메소드로 허용했습니다.


0

이론상 나쁜 생각은 아니지만 구현할 때 옵션을 제한하는 부정적인 부작용이 있습니다 D. 예를 들어, 어떤 경우 (명확한 이유로) F다른 메소드에서 수퍼 클래스 구현을 호출하는 것이 더 편리합니다 .

class D inherits C
    override F
        statement1
        statement2
        G()
    G
        statement3
        C.F()
        statement4

귀하의 시나리오에서 컴파일러가 Fin 의 구현을 D간접적으로 호출하더라도 플래그를 구현한다고 상상합니다 C.F().

기본적으로 설명 한 것은 상속 클래스에 대한 계약을 C위반 했을 때 컴파일러가 인식하도록 돕는 가능한 메커니즘 입니다. 내 요점은 그것이 큰 일이지만 내 서브 클래스를 구현할 수있는 방법 을 제한 하는 비용을 들이지 않아야한다는 것 입니다.


1
-1 : 당신이 사용하고 싶지 않은 상황을 생각할 수 있다는 것은 "어떤 언어가 그것을 허용합니까?"라는 질문에 대한 대답이 아닙니다.

@GrahamLee : 매우 그렇습니다. 내 요점은 내가 아는 언어가 그러한 기능을 구현하지 않는 한 가지 이유를 시도하고 설명하는 것이 었습니다. 나는 그것을 설명하는 데 너무 빠져있어서 내가 그것을 설명하는 이유 를 언급하는 것을 잊어 버렸습니다 . -1 행복하게 받아 들였다. :)
Mac
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.