추상 클래스의 모든 공용 메소드를 가상으로 표시해야합니까?


12

나는 최근에 내가 사용하고있는 일부 OSS에서 추상 기본 클래스를 업데이트하여 가상으로 만들어서 더 테스트 할 수 있도록해야했습니다 (두 인터페이스를 결합하여 인터페이스를 사용할 수 없었습니다). 이를 통해 가상이 필요한 모든 방법을 표시해야하는지 또는 모든 공용 방법 / 속성 가상을 표시해야하는지 생각하게되었습니다. 나는 일반적으로 모든 방법을 가상되어야한다고 로이 Osherove에 동의하지만, 나는 나에 필요 여부인지에 대해 생각을 가지고이 글을 우연히 만났다 . 단순성을 위해 이것을 추상 클래스로 제한하려고합니다 (모든 구체적인 공개 메소드가 가상이어야하는지 여부는 확실하지만 논쟁의 여지가 있습니다).

하위 클래스가 메소드를 사용하도록 허용하고 싶지만 구현을 재정의하고 싶지는 않은 것을 알 수 있습니다. 그러나 Liskov의 대체 원칙 을 따를 것이라고 신뢰하는 한 왜이를 대체하지 않겠습니까? 그것을 추상으로 표시함으로써 어쨌든 특정 재정의를 강요하므로 추상 클래스 내부의 모든 공개 메소드는 실제로 가상으로 표시되어야합니다.

그러나, 내가 생각하지 않을 수도있는 것이 있으면 물어보고 싶었다. 추상 클래스 내의 모든 공개 메소드를 가상으로 만들어야합니까?


도움이 될 수 있습니다 : stackoverflow.com/questions/391483/…
NoChance

1
어쩌면 C #에서 기본값이 가상이 아닌 Java 인 이유를 조사해야합니다. 아마도 당신에게 대답에 대한 통찰력을 줄 수있는 이유.
Daniel Little

답변:


9

그러나 Liskov의 대체 원칙을 따를 것이라고 신뢰하는 한 왜이를 대체하지 않겠습니까?

예를 들어 알고리즘의 골격 구현을 고정하고 하위 클래스로 특정 부분 만 (재) 정의 할 수 있기를 원하기 때문입니다. 이것은 템플릿 방법 패턴 (아래에서 강조) 으로 널리 알려져 있습니다 .

따라서 템플릿 방법은 작업 의미론의 더 큰 그림과 방법 선택 및 순서에 대한보다 정교한 구현 세부 정보를 관리합니다. 이 큰 그림은 당면 과제에 대한 추상적이고 비 추상적 인 방법을 호출합니다. 비추 상 메소드는 템플릿 메소드에 의해 완전히 제어되지만 서브 클래스로 구현 된 추상 메소드는 패턴의 표현력과 자유도를 제공합니다. 추상 메소드의 일부 또는 전부는 서브 클래스에 특화되어 서브 클래스의 작성자가 더 큰 의미에 대한 최소한의 수정으로 특정 동작을 제공 할 수 있습니다. 템플릿 패턴 (추상적이지 않은)은이 패턴에서 변경되지 않은 상태로 유지되어 하위 비 추상적 메서드와 추상 메서드가 원래 의도 된 순서로 호출되도록합니다.

최신 정보

내가 작업 한 프로젝트의 구체적인 예 :

  1. 다양한 "화면"을 통해 레거시 메인 프레임 시스템과 통신 각 화면에는 특정 데이터 비트를 포함하는 고정 된 이름, 위치 및 길이의 여러 필드가 있습니다. 요청은 특정 필드로 특정 데이터를 채 웁니다. 응답은 하나 이상의 다른 필드에서 데이터를 반환합니다. 각 트랜잭션은 동일한 기본 논리를 따르지만 세부 정보는 화면마다 다릅니다. 우리는 여러 가지 프로젝트에서 템플릿 메소드를 사용하여 화면 처리 논리의 고정 된 골격을 구현하면서 서브 클래스가 화면 특정 세부 사항을 정의 할 수 있도록했습니다.
  2. DB 테이블의 구성 데이터를 Excel 파일로 내보내거나 가져 오기 다시 한 번, Excel 파일을 처리하고 DB 레코드를 삽입 / 업데이트하거나 레코드를 Excel에 덤프하는 기본 스키마는 각 테이블마다 동일하지만 각 테이블의 세부 사항은 다릅니다. 따라서 템플릿 방법은 코드 중복을 제거하고 코드를 이해하고 유지하기 쉽게 만드는 매우 확실한 선택입니다.
  3. PDF 문서 생성 각 문서는 동일한 구조를 갖지만 많은 요소에 따라 매번 내용이 다릅니다. 다시, 템플릿 방법을 사용하면 생성 알고리즘의 고정 된 스켈레톤을 사례 별 변경 가능한 세부 정보와 쉽게 분리 할 수 ​​있습니다. 사실로. 문서가 여러 섹션 으로 구성되어 있으며 각 섹션 은 0 개 이상의 필드 로 구성 되어 있으므로 여기에서는 여러 수준에 적용됩니다 . 템플릿 방법은 여기에 3 가지 레벨로 적용됩니다.

처음 두 사례에서 원래의 레거시 구현은 Strategy를 사용 하여 코드가 많이 복제되었습니다. 물론 몇 년 동안 여기저기서 미묘한 차이가 생겨나 고 복제되거나 약간 다른 버그가 많이 있었고 유지하기가 매우 어려웠습니다. 템플릿 방법으로 리팩토링 (및 Java 주석 사용과 같은 일부 다른 기능 향상)으로 코드 크기를 약 40-70 % 줄였습니다.

이것들은 내 생각에 가장 최근의 예일뿐입니다. 지금까지 작업 한 거의 모든 프로젝트에서 더 많은 사례를 인용 할 수있었습니다.


단순히 GoF를 인용하는 것은 답이 아닙니다. 그러한 일을하는 실제적인 이유를 제시해야합니다.
DeadMG

@DeadMG, 나는 경력 기간 동안 템플릿 방법을 정기적으로 사용 해 왔으므로 매우 실용적이고 유용한 패턴이라는 것이 분명하다고 생각했습니다. 실제 경험에서). 그러나 분명히 모든 사람들이 그것에 동의하지는 않습니다 ... 그래서 나는 내 대답에 몇 가지 구체적인 예를 추가합니다.
Péter Török

2

완벽하게 합리적이며 때로는 추상 기본 클래스에 비가 상 메소드를 갖는 것이 바람직합니다. 추상 클래스이기 때문에 반드시 모든 부분을 다형성으로 사용할 수 있어야하는 것은 아닙니다.

예를 들어, 가상 함수가 호출되기 전에 특정 전제 조건 또는 사후 조건이 충족되도록하기 위해 비가 상 멤버 함수에서 함수를 다형성 적으로 호출하는 '비가 상 다형성'관용구를 사용할 수 있습니다.

class MyAbstractBaseClass
{
protected:
    virtual void OverrideMe() = 0;
public:
    void CallMeFirst();

    void CallMe()
    {
        CallMeFirst();
        OverrideMe();
    }
};

전반적인 행동이 동일하게 유지되는 한, 이것은 가상이 될 수 있다고 주장합니다. 다른 구현 (데이터베이스 대 인 메모리)을 사용하여 사전 / 사후 조건을 채울 수 있습니다. 그렇지 않으면 개인 기능이어야합니까?
저스틴 피 호니

2

클래스가 추상이 되려면 클래스에 하나의 가상 메소드를 포함하는 것으로 충분합니다. 사용하려는 다형성의 유형에 따라 가상에서 원하는 방법과 그렇지 않은 방법에주의를 기울일 수 있습니다.


1

추상 클래스에서 비가 상 메소드의 용도가 무엇인지 스스로에게 물어보십시오. 이러한 메소드는 유용하게 구현되어야합니다. 그러나 클래스에 구현이 있으면 여전히 추상 클래스라고 할 수 있습니까? 언어 / 컴파일러가 허용하더라도 이해가됩니까? 개인적으로는 그렇게 생각하지 않습니다. 자손이 구현할 것으로 예상되는 추상 메소드가있는 일반 클래스가 있습니다.

내 주요 언어는 C #이 아닌 Delphi입니다. 델파이에서는 메소드 추상을 표시하면 가상으로 표시하거나 컴파일러가 불평합니다. 최신 언어 변경 사항을 너무 밀접하게 따르지 않았지만 추상 클래스가 델파이에 있거나 델파이에 올 경우 컴파일러는 가상이 아닌 메소드, 개인 메소드 및 추상적으로 표시된 클래스의 메소드 구현에 대해 불평 할 것으로 기대합니다 수업 수준에서.


2
추상적 인 메소드, 가상 메소드 및 비가 상 메소드를 갖는 추상적 클래스를 갖는 것이 완벽하다고 생각합니다. 나는 그것이 정확히 무엇을하고 싶은지에 달려 있다고 생각합니다.
svick

3
먼저 C # q를 살펴 보겠습니다. C #의 추상 메서드는 암시 적으로 가상이므로 구현할 수 없습니다. 첫 번째 요점에서 C #의 추상 클래스는 일종의 구현을 가질 수 있으며 구현해야합니다 (그렇지 않으면 인터페이스를 사용해야합니다). 추상적 인 클래스의 요점은 반드시 서브 클래 싱되어야한다는 것입니다. 그러나 모든 서브 클래스가 (이론적으로) 사용할 논리를 포함합니다. 코드 중복이 줄어 듭니다. 내가 묻는 것은 그 구현 중 어느 것이 재정의되는 것을 막아야하는지 여부입니다 (기본적으로 유일한 방법이라고 말합니다).
저스틴 피 호니

@JustinPihony : 감사합니다. 델파이에서는 메소드 추상을 표시 할 때 구현을 제공하면 컴파일러에서 불만을 표시합니다. 서로 다른 언어가 어떻게 개념을 다르게 구현하여 사용자에게 다른 기대를하는지에 관심이 있습니다.
Marjan Venema

@ svick : 그렇습니다. 완벽한 의미가 있습니다. 추상 클래스라고 부르지는 않지만 추상 메소드가있는 클래스입니다 ...하지만 그건 내 해석 일 수 있습니다.
Marjan Venema

@MarjanVenema이지만 C #에서 사용하는 용어는 아닙니다. 클래스에서 메소드를 abstract표시하는 경우 전체 클래스도 표시해야합니다 abstract.
svick April

0

그러나 Liskov의 대체 원칙을 따를 것이라고 믿는 한, 왜 그것을 대체하지 않겠습니까?

이것이 사실이라고 믿지 않기 때문에 특정 방법을 가상으로 만들지 않습니다. 또한 특정 메서드를 가상이 아닌 것으로 만들어 상속자에게 어떤 메서드를 구현해야하는지 신호를 보냅니다.

개인적으로, 나는 종종 가상이 아닌 편의를 위해 존재하는 메소드 오버로드를 만들어 클래스의 사용자가 일관된 기본값을 가질 수 있고 구현자는 암시 적 동작을 중단시키는 오류조차 만들 수 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.