상속을 언제 중단해야합니까?


9

옛날 옛적에 나는 상속에 대해 Stack Overflow 에 대해 질문했다 .

체스 엔진을 OOP 방식으로 디자인한다고 말했습니다. 그래서 나는 조각 추상 클래스에서 모든 조각을 상속 받지만 상속은 여전히 ​​계속됩니다. 코드로 보여 드리겠습니다

public abstract class Piece
{
    public void MakeMove();
    public void TakeBackMove();
}

public abstract class Pawn: Piece {}

public class WhitePawn :Pawn {}

public class BlackPawn:Pawn {}

프로그래머는 저의 디자인이 엔지니어링보다 약간 이상하다는 것을 알았으며 아래 그림과 같이 색상 조각 클래스를 제거하고 조각 색상을 속성 멤버로 유지하는 것이 좋습니다.

public abstract class Piece
{
    public Color Color { get; set; }
    public abstract void MakeMove();
    public abstract void TakeBackMove();
}

이런 식으로 Piece는 그의 색을 알 수 있습니다. 구현 후 내 구현이 아래와 같이 진행되는 것을 보았습니다.

public abstract class Pawn: Piece
{
    public override void MakeMove()
    {
        if (this.Color == Color.White)
        {

        }
        else
        {

        }
    }

    public override void TakeBackMove()
    {
        if (this.Color == Color.White)
        {

        }
        else
        {

        }
    }
}

이제 구현에서 if 문을 유발하는 색상 속성을 유지하는 것을 볼 수 있습니다. 상속 계층 구조에서 특정 색상 조각이 필요하다고 생각합니다.

이 경우 WhitePawn, BlackPawn과 같은 클래스가 있습니까? 아니면 Color 속성을 유지하여 디자인을 하시겠습니까?

그런 문제를 보지 않으면 어떻게 디자인을 시작하고 싶습니까? 색상 속성을 유지하거나 상속 솔루션이 있습니까?

편집 : 내 예제가 실제 예제와 완전히 일치하지 않도록 지정하고 싶습니다. 따라서 구현 세부 정보를 추측하기 전에 질문에 집중하십시오.

실제로 Color 속성을 사용하면 if 문이 상속을 더 잘 사용할 수 있는지 묻습니다.


3
나는 왜 당신이 이런 식으로 모델을 만들지 이해하지 못합니다. MakeMove ()를 호출하면 어떤 동작을 수행합니까? 난 당신이 정말 보드의 상태를 모델링되어 시작하고 당신이 그것을 위해 필요한 클래스를 볼 필요가 무엇을 말할 것
JK.

11
나는 당신의 기본적인 오해가 체스에서 "컬러"가 실제로 조각이 아니라 플레이어의 속성이라는 것을 깨닫지 못한다고 생각합니다. 그렇기 때문에 우리는 "blacks move"등을 말하며, 그 조각을 소유 한 플레이어를 식별하기 위해 채색이 이루어집니다. 폰은 색이 어떤 방향이든지 상관없이 같은 움직임 규칙과 제한을 따릅니다. 유일한 변형은 "방향"입니다.
James Anderson

5
상속을 "정지 할 때"파악할 수 없을 때는 완전히 삭제하는 것이 좋습니다. 계층 구조가 명확 해지면 나중에 디자인 / 구현 / 유지 보수 단계에서 상속을 다시 도입 할 수 있습니다. 나는이 접근법을 사용하고, 매력처럼 작동한다
gnat

1
더 어려운 문제는 각 조각 유형에 대한 하위 클래스를 만들지 여부입니다. 조각 유형은 조각 색상보다 더 많은 행동 양상을 결정합니다.
NoChance

3
ABC (Abstract Base Classes)로 디자인을 시작하려는 유혹이 있다면 우리 모두에게 호의를 베풀지 말아야합니다 ... ABC가 실제로 유용한 경우는 매우 드물고 심지어 인터페이스를 사용하는 것이 더 유용합니다. 대신에.
Evan Plaice

답변:


12

차량이 포함 된 응용 프로그램을 설계한다고 가정하십시오. 이런 식으로 만들었습니까?

class BlackVehicle : Vehicle { }
class DarkBlueVehicle : Vehicle { }
class DarkGreenVehicle : Vehicle { }
// hundreds of other classes...

실제로 색상은 객체 (자동차 또는 체스 조각)의 속성이며 속성으로 표시되어야합니다.

인가 MakeMoveTakeBackMove흑인과 백인 다른? 전혀 아님 : 규칙은 두 선수 모두 동일합니다. 즉,이 두 가지 방법은 흑백에 대해 정확히 동일하므로 필요하지 않은 조건을 추가하고 있습니다.

당신이있는 경우 반면에, WhitePawn그리고 BlackPawn, 나는 경우 곧 놀라지 않을 것 이상 당신은 쓸 것이다 :

var piece = (Pawn)this.CurrentPiece;
if (piece is WhitePawn)
{
}
else // The pice is of type BlackPawn
{
}

또는 심지어 다음과 같은 것 :

public abstract class Pawn
{
    public Color Player
    {
        get
        {
            return this is WhitePawn ? Color.White : Color.Black;
        }
    }
}

// Now imagine doing the same thing for every other piece.

4
@Freshblood 나는 direction속성 을 가지고 그것을 사용하여 색상 속성을 사용하는 것보다 이동 하는 것이 더 낫다고 생각합니다 . 색상은 논리가 아닌 렌더링에만 사용하는 것이 이상적입니다.
Gyan 일명 Gary Buy

7
게다가 조각들은 같은 방향으로 앞으로, 뒤로, 왼쪽, 오른쪽으로 움직입니다. 차이점은 시작하는 보드의 측면과 다릅니다. 도로에서는 반대 차선의 차량이 모두 앞으로 움직입니다.
slipset

1
@Blrfl 당신은 그 direction속성이 부울 일 수도 있습니다 . 나는 무엇이 잘못되었는지 알지 못한다. Freshblood가 위에서 언급 할 때까지이 질문에 대해 혼란 스러웠던 점은 색상에 따라 움직임 논리를 바꾸고 싶은 이유입니다. 나는 색이 행동에 영향을 미치는 것이 의미가 없기 때문에 이해하기가 더 어렵다고 말할 것입니다. 당신이하고 싶은 것은 어떤 플레이어가 어떤 조각을 소유하고 있는지 구별하는 것입니다. 당신은 그것들을 두 개의 분리 된 컬렉션에 넣을 수 있고 재산이나 상속의 필요성을 피할 수 있습니다. 조각 자체는 그들이 속한 플레이어를 행복하게 알지 못할 수 있습니다.
Gyan 일명 게리 Buyed

1
우리는 두 가지 관점에서 같은 것을보고 있다고 생각합니다. 양면이 빨간색과 파란색 이면 흑백 일 때와 다른 동작을합니까? 나는 아니오라고 말할 것입니다. 이것이 색상이 행동상의 차이의 원인이 아니라고 말하는 이유입니다. 그것은 단지 미묘한 차이입니다하지만 난을 사용하는 이유는 direction어쩌면 나 player대신의 속성을 color게임 로직을 하나.
Gyan 일명 Gary Buy 8

1
@Freshblood- white castle's moves differ from black's어떻게? 캐슬 링을 의미합니까? King-side castling과 Queen-side castling은 모두 흑백에 대해 100 % 대칭입니다.
Konrad Morawski

4

자신에게 물어보아야 할 것은 Pawn 클래스에서 이러한 진술이 실제로 필요한 이유입니다.

    if (this.Color == Color.White)
    {

    }
    else
    {
    }

나는 그것이 같은 작은 기능 세트를 갖는 것으로 충분하다고 확신한다

public abstract class Piece
{
    bool DoesPieceHaveSameColor(Piece otherPiece) { /*...*/   }

    Color OtherColor{get{/*...*/}}
    // ...
}

위의 문장 을 사용하지 않고도 해당 함수를 사용 하여 Piece 클래스에서 모든 함수 Pawn(및 기타 파생물 Piece)를 구현하십시오 if. 폰에 따라 폰의 이동 방향을 결정하는 기능은 예외 일 수 있습니다. 폰에 따라 다르기 때문에 거의 모든 경우에 색별 코드가 필요하지 않습니다.

다른 흥미로운 질문은 다른 종류의 조각에 대해 다른 서브 클래스를 실제로 가지고 있어야하는지입니다. 각 조각의 이동 규칙이 다르기 때문에 합리적이고 자연스럽게 보입니다. 각 종류의 조각에 대해 서로 다른 오버로드 함수를 사용하여이를 구현할 수 있습니다.

물론, 하나는 자신의 이동 규칙에서 조각의 속성을 분리하여,보다 일반적인 방법으로이 모델을 시도 할 수 있지만,이 추상 클래스에 끝날 수 MovingRule와 서브 클래스 계층 구조 MovingRulePawn, MovingRuleQueen... 나는 그것을 시작할 것이라고 다른 형태의 오버 엔지니어링으로 쉽게 이어질 수 있기 때문입니다.


색상 별 코드를 지적하면 +1이 될 것입니다. 흰색과 검은 색 폰은 다른 모든 조각과 마찬가지로 본질적으로 동일한 방식으로 작동합니다.
Konrad Morawski

2

상속이 개체의 외부 기능에 영향을 미치지 않는 경우 상속은 유용하지 않습니다 .

Color 속성은 Piece 개체 사용 방법에 영향을 미치지 않습니다 . 예를 들어, 모든 조각은 이동이 합법적이지 않은 경우에도 moveForward 또는 moveBackwards 메서드를 호출 할 수 있지만 조각의 캡슐화 된 논리는 Color 속성을 사용하여 앞으로 또는 뒤로 이동을 나타내는 절대 값을 결정합니다 (-1 또는 + API에 관한 한, 수퍼 클래스와 서브 클래스는 동일한 객체입니다 (모두 동일한 메소드를 노출하므로).

개인적으로 각 조각 유형을 나타내는 상수를 정의한 다음 switch 문을 사용하여 "this"인스턴스에 대해 가능한 이동을 반환하는 개인 메서드로 분기합니다.


뒤로 이동하는 것은 폰의 경우에만 불법입니다. 그리고 그들은 검은 색인지 흰색인지 알 필요가 없습니다. 앞뒤를 구별하기에 충분하고 논리적입니다. Board(예) 클래스는 조각의 색에 따라 이들 개념에 -1 또는 +1 변환을 담당 할 수있다.
Konrad Morawski

0

개인적으로 나는 아무것도 상속받지 Piece않을 것입니다. 왜냐하면 당신이 그렇게하면 아무것도 얻지 못한다고 생각하기 때문입니다. 아마도 조각은 실제로 어떻게 움직이는 지 신경 쓰지 않으며 다음 이동을 위해 유효한 사각형 만 결정합니다.

아마도 유형의 조각에 사용 가능한 이동 패턴을 알고 유효한 대상 사각형의 목록을 검색 할 수있는 유효한 이동 계산기 를 만들 수 있습니다.

interface IMoveCalculator
{
    List<Square> GetValidDestinations();
}

class KnightMoveCalculator : IMoveCalculator;
class QueenMoveCalculator : IMoveCalculator;
class PawnMoveCalculator : IMoveCalculator; 
// etc.

class Piece
{
    IMoveCalculator move_calculator;
public:
    Piece(IMoveCalculator mc) : move_calculator(mc) {}
}

그러나 누가 어떤 조각을 움직일 수 있는지 결정합니까? 피스베이스 클래스를 가지고 있고 PawnPiece를 가지고 있다면, 그 가정을 할 수 있습니다. 그러나 그 속도로, 작품 자체는 원래의 질문에 설계된대로, 이동 방법을 구현할 수
스티븐 Striga에게

@WeekendWarrior- "개인적으로는 전혀 아무것도 상속하지 않습니다 Piece." Piece는 단순히 움직임을 계산하는 것 이상을 담당하는 것 같습니다. 이것이 움직임을 별도의 관심사로 분리하는 이유입니다. 어떤 계산기가 어떤 계산기를 가져 와서 의존성 주입의 문제가되는지 결정하기. 예 :var my_knight = new Piece(new KnightMoveCalculator())
Ben Cottrell

플라이급 패턴에 적합한 후보입니다. 체스 판에는 16 개의 폰이 있으며 모두 같은 동작을 공유합니다 . 이 동작은 단일 플라이급으로 쉽게 추출 할 수 있습니다. 다른 모든 부분도 마찬가지입니다.
MattDavey

-2

이 답변에서, 나는 "체스 엔진"에 의해 질문의 저자는 단지 이동 검증 엔진이 아니라 "체스 AI"를 의미한다고 가정한다.

나는 조각과 유효한 움직임에 OOP를 사용하는 것이 두 가지 이유로 나쁜 생각이라고 생각합니다.

  1. 체스 엔진의 강점은 보드를 얼마나 빠르게 조작 할 수 있는지에 따라 크게 달라집니다 (예 : 체스 프로그램 보드 표현 참조) . 이 기사에서 설명하는 최적화 수준을 고려할 때 정규 함수 호출이 저렴하다고 생각하지 않습니다. 가상 메서드를 호출하면 간접적 인 수준이 추가되고 성능이 저하 될 수 있습니다. OOP 비용은 저렴하지 않습니다.
  2. 체스는 곧 새로운 조각을 얻을 수 없기 때문에 확장 성과 같은 OOP의 이점은 조각에 사용되지 않습니다. 상속 기반 형식 계층의 대안으로 열거 형과 스위치를 사용할 수 있습니다. 기술 수준이 낮고 C와 비슷하지만 성능 측면에서는 이길 수 없습니다.

유형 계층 구조에서 조각의 색상을 포함하여 성능 고려 사항에서 벗어나는 것은 나쁜 생각입니다. 캡처와 같이 두 조각의 색상이 다른지 확인해야하는 상황에 처할 수 있습니다. 이 조건을 확인하는 것은 속성을 사용하여 쉽게 수행 할 수 있습니다. is WhitePiece-tests를 사용하면 비교가 더 어려워집니다.

이동 동작 생성을 조각 특정 방법으로 피하는 또 다른 실질적인 이유가 있습니다. 즉, 다른 조각이 공통 동작 (예 : 루크 및 여왕)을 공유하기 때문입니다. 중복 코드를 피하려면 공통 코드를 기본 메소드로 인수 분해해야하며 비용이 많이 드는 또 다른 호출이 필요합니다.

즉, 처음 작성하는 체스 엔진이라면 깨끗한 프로그래밍 원칙을 따르고 Crafty의 저자가 설명 한 최적화 트릭을 피하는 것이 좋습니다. 체스 규칙 (캐스팅, 판촉, 난폭 한)과 복잡한 AI 기술 (해시 보드, 알파-베타 컷)의 세부 사항을 다루는 것은 충분히 어려운 일입니다.


1
체스 엔진을 너무 빨리 쓰는 것은 목적이 아닐 수도 있습니다.
Freshblood

5
-1. "가설 적으로는 성능 문제가 될 수 있으므로 좋지 않습니다"와 같은 판단은 거의 항상 순수한 미신입니다. 그리고 상속은 당신이 언급 한 의미에서 "확장 성"에 관한 것이 아닙니다. 다른 체스 규칙은 다른 조각에 적용되며, 방법의 다른 구현을 가진 각 종류의 조각 WhichMovesArePossible은 합리적인 접근 방식입니다.
Doc Brown

2
확장 성이 필요하지 않은 경우 가상 메소드 디스패치보다 빠르기 때문에 스위치 /에 기반한 접근 방식이 선호됩니다. 체스 엔진은 CPU를 많이 사용하므로 가장 자주 (따라서 효율성이 중요한) 작업은 이동을 수행하고 실행 취소하는 것입니다. 그보다 한 단계 위의 모든 가능한 움직임을 나열합니다. 나는 이것이 또한 시간이 중요 할 것으로 예상한다. 사실, 저는 C로 체스 엔진을 프로그래밍했습니다. OOP가 없어도 보드 표현에 대한 저수준 최적화가 중요했습니다. 어떤 경험을 해산해야합니까?
Joh

2
@Joh : 나는 당신의 경험을 무시하지 않을 것이지만, 그것이 OP 이후의 것이 아니라고 확신합니다. 저수준 최적화는 몇 가지 문제에서 중요 할 수 있지만, 특히 성능 문제에 직면하지 않은 경우이를 고수준 설계 결정의 기초로 삼는 것은 실수라고 생각합니다. 제 경험은 Knuth가 "조기 최적화는 모든 악의 근원"이라고 말할 때 매우 옳았습니다.
Doc Brown

1
-1 Doc에 동의해야합니다. 사실, OP가 말하고있는이 "엔진"은 단순히 2 인용 체스 게임을위한 검증 엔진 일 수 있습니다. 이 경우 OOP의 성능과 다른 스타일의 성능에 대한 생각은 완전히 어리석은 일이지만 간단한 ARM 디바이스에서도 순간의 간단한 유효성 검사에 밀리 초가 걸립니다. 실제로 언급 된 것보다 요구 사항을 자세히 읽지 마십시오.
Timothy Baldridge
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.