상속이 잘못되었습니다


12

좋은 상속 모델이 내리막 길에 코드가 있는데 왜 그리고 어떻게 수정 해야하는지 이해하려고합니다. 기본적으로 다음과 같은 Zoo 계층 구조가 있다고 가정하십시오.

class Animal  
class Parrot : Animal 
class Elephant : Animal 
class Cow : Animal

기타

eat (), run () 등의 메소드가 있으며 모두 좋습니다. 언젠가 누군가가 와서 말하기를-우리의 CageBuilder 클래스는 너무 강력하고 벽을 산산조각 낼 수있는 새로운 아프리카 들소를 제외하고는 잘 작동하고 animal.weight () 및 animal.height ()를 사용합니다. Animal 클래스에 대한 하나 이상의 속성 인 isAfricanBizon ()을 선택하고 재료를 선택할 때이를 사용하고 AfricanBizon 클래스에 대해서만 재정의하십시오. 다음 사람이 와서 비슷한 일을하고 다음으로 당신은 기본 클래스에 대한 계층의 일부 하위 집합에 대해 이러한 모든 속성을 가지고 있음을 알고 있습니다.

그러한 코드를 개선 / 리팩터링하는 좋은 방법은 무엇입니까? 여기서 한 가지 대안은 dynamic_casts를 사용하여 유형을 확인하는 것이지만 발신자를 혼란스럽게 만들고 다른 곳에 if-then-else를 추가합니다. 여기에 더 구체적인 인터페이스를 가질 수는 있지만 기본 클래스 참조 만 있으면 도움이되지 않습니다. 다른 제안? 예?

감사!


@ 제임스 : 그러면 파서를 직접 작성해야합니다. : S
Matteo Italia

5
분명히 이것은 터무니없는 고객 요구 사항의 경우입니다. 아프리카에는 들소가 없습니다. 현실과 연결되지 않은 객체 모델을 설계 할 수 없습니다. 그 현실이 달러로 가득 찬 손으로 만들어지지 않는 한. 어느 것이 문제를 해결합니다.
Hans Passant

1
들소를 다 먹어? [나는 이전에이 게시하지만 몇 가지 이유가 아마도 유머 얼간에 의해 삭제에 대한했다.]
제임스 McNellis

CageBuilder에는 자체 클래스가 필요합니까? 각 개별 클래스에서 재정의 할 수있는 기본 MakeCage 메서드가 있으면 어떻게됩니까?
Job

1
if-then-else 클러 터를 호출자의 단점으로 언급하지만 호출자가 isAfricanBizon ()을 사용하자마자 if-then-else로 코드를 자동으로 어지럽 힙니다. 따라서 isAfricanBizon ()을 사용하는 if-then-else 클러 터이거나 동적 캐스트를 사용하는 if-then-else 클러 터입니다.
davidk01

답변:


13

문제는 requireConcreteWall ()을 구현하는 대신 깃발 호출 IsAfricanBison ()을 구현 한 다음 벽이 클래스 범위 밖에서 변경되어야하는지 여부에 대한 논리를 이동 한 것 같습니다. 수업은 정체성이 아닌 행동과 요구 사항을 노출해야합니다. 이 클래스의 소비자는 자신이 무엇을 기초로하지 않고 자신이 말하는 내용으로 작업해야합니다.


1
-1 : 하지 말아야 할 말만합니다. OP는 이미 이것이 나쁜 생각이라는 것을 알고 있으므로 문제입니다.
Steven Evers

12

isAfricanBizon ()은 일반적이지 않습니다. 너무 강력하지만 isAfricanBizon ()에서 true를 반환하여 적절한 효과를 거두는 최면으로 동물 농장을 확장한다고 가정 해보십시오.

항상 특정 질문에 대답하는 메소드를 인터페이스에 추가하려고합니다.이 경우 strength ()와 같습니다.


+1 : 다른 사람들은이 특정 사용 사례를 수용하기 위해 클래스의 개념적 모델 (다른 종류의 동물의 속성을 캡슐화 함)을 깨는 것 같습니다. 에 strength의해 material.canHold(animal)다른 종류의 재료를 깔끔하게 지원할 수있는 방법을 사용하여 쿼리 할 수 ​​있습니다 ConcreteWall.
Aidan Cully

나는 향후 요구 사항을 활성화하는 데 더 유연하기 때문에 strength () 속성 접근 방식이 다른 사람들의 NeedConcreteWall () 제안보다 더 좋습니다. 우선 CageBuilder 클래스가 어떤 재료가 충분히 강한지를 결정하게 한 다음 새로운 재료로 클래스를 쉽게 확장 할 수 있습니다.
jhocking

3

문제는 이것이라고 생각합니다. 계층의 하위 집합에만 관심이 있지만 기본 클래스에 대한 포인터 / 참조가 전달되는 라이브러리의 다양한 클라이언트가 있습니다. 그것은 사실 dynamic_cast <>가 해결해야 할 문제입니다.

dynamic_cast <>의 사용을 최소화하는 것은 클라이언트 설계의 문제입니다. 객체가 특별한 처리가 필요한지 여부와 다운 캐스트 된 참조에 대한 모든 작업이 필요한지 여부를 결정하는 데 사용해야합니다.

여러 개의 개별 하위 계층 구조에 적용되는 "혼합"유형의 기능 모음이있는 경우 Java 및 C #에서 사용하는 인터페이스 패턴을 사용할 수 있습니다. 순수 가상 클래스 인 가상 기본 클래스를 보유하고 dynamic_cast <>를 사용하여 인스턴스가 구현을 제공하는지 판별하십시오.


1

isAfricanBison()실제로 관심있는 속성을 확인하는 것과 같이 유형의 명시 적 확인을 바꾸는 것이 가능합니다 isTooStrong().


1
무엇에 대한 isTooStrong ()? 케이지 특정 코드를 동물 클래스에 추가하고 있습니다.
Steven Evers

1

동물은 콘크리트 벽을 신경 쓰지 않아야합니다. 간단한 값으로 표현할 수도 있습니다.

class Animal {
public:
  virtual ~Animal() {}
  virtual size_t height() const = 0;
  virtual size_t weight() const = 0;
  virtual bool isStrong() const = 0;
};

Cage *CreateCageFromSQL(Animal &a);
Cage *CreateCageFromOrangePeelsAndSticks(Animal &a);

나는 그것이 가능하지 않다고 생각합니다. 그러나 장난감 예제의 문제입니다.

나는 절대로 ConConteteWalls () 또는 동적 포인터 캐스트의 라인과 라인을보고 싶지 않습니다.

이것은 일반적으로 저렴한 솔루션입니다. 유지 관리 및 개념화가 쉽습니다. 그리고 실제로, 문제는 그것이 어쨌든 동물 유형에 묶여 있음을 나타냅니다.

class Animal {
public:
  virtual ~Animal() {}
  virtual CageBuilder *getCageBuilder() = 0;
};

이것은 공유 코드 사용을 방해하지 않으며 Animal을 약간 오염시킵니다.

그러나 우리가 만들어지는 방법은 다른 시스템의 정책 일 수 있으며, 동물 당 하나 이상의 유형의 우리를 만들 수도 있습니다. 당신이 얻을 수있는 이상하고 복잡한 조합이 많이 있습니다.

나는 Component Based Design 을 좋은 목적으로 사용했는데 , 그것의 주된 문제는 Animal의 소유권이 공유 될 때 문제가 될 수 있다는 것입니다. 소멸자가 던지는 것을 피하는 법

Double Dispatch 는 또 다른 옵션이지만 항상 뛰어 들었습니다.

그 외에도 문제를 추측하기가 어렵습니다.


0

확실히 모든 동물은 고유 속성을가 attemptEscape()집니다. 일부 방법은 포즈 수 있지만 false다른 사람이 같은 그들의 다른 고유의 특성을 추론의 기반으로 기회가있을 수 있습니다 동안 모든 시나리오의 결과 sizeweight. 그렇다면 어느 시점에서 attemptEscape()가장 확실하게 돌아올 것이기 때문에 사소한 것이됩니다 true.

나는 당신의 질문을 완전히 이해하지 못합니다 ... 모든 동물은 관련된 행동과 특성을 가지고 있습니다. 동물에 맞는 동물을 적합한 곳에 소개해야합니다. Bison을 Parrots와 직접 연관시키는 것은 좋은 설치 방법이 아니며 적절한 디자인에 문제가되지 않아야합니다.


-1

다른 옵션은 각 동물에 적합한 케이지를 만드는 공장을 사용하는 것입니다. 조건이 각 조건마다 매우 다른 경우에는 이것이 더 나을 수 있다고 생각합니다. 그러나 이것이 단지 하나의 조건이라면 위에서 언급 한 RequiresConcreteWall()방법이 그렇게 할 것입니다.


-1

ContainsConcreteWall ()에 따라 RecommendCageType ()은 어떻습니까?


-2

왜 이런 짓을하지

class Animals { /***/ } class HeavyAnimals{} : Animals //The basic class for animals like the African Bison

HeavyAnimals 클래스를 사용하면 HeavyAnimals 클래스를 확장하여 African Bison 클래스를 만들 수 있습니다.

이제 여러분은 HeavyAnimal 클래스와 같은 다른 기본 클래스를 만드는 데 사용할 수있는 부모 클래스 (동물)를 사용하여 아프리카 들소 클래스와 다른 무거운 동물을 만들 수 있습니다. 따라서 아프리카 들소를 사용하면 이제 동물 클래스 방법과 속성 (모든 동물의 기초)과 HeavyAnimals 클래스 (무거운 동물의 기초)에 액세스 할 수 있습니다.


2
그것은 믹스 인 또는 특성으로 작동 할 수 있지만 확실히 하위 클래스로는 작동하지 않습니다. 다음 번에 다른 속성이 필요할 때 다중 상속을 요청합니다.
Ordous
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.