객체 지향 디자인


23

다음이 있다고 가정하십시오.

     +--------+     +------+
     | Animal |     | Food |
     +-+------+     +----+-+
       ^                 ^
       |                 |
       |                 |
  +------+              +-------+
  | Deer |              | Grass |
  +------+              +-------+

Deer에서 상속 AnimalGrass상속합니다 Food.

여태까지는 그런대로 잘됐다. Animal물건을 먹을 수 Food있습니다.

이제 조금 섞어 봅시다. Lion에서 상속되는 a 를 추가 할 수 있습니다 Animal.

     +--------+     +------+
     | Animal |     | Food |
     +-+-----++     +----+-+
       ^     ^           ^
       |     |           |
       |     |           |
  +------+ +------+     +-------+
  | Deer | | Lion |     | Grass |
  +------+ +------+     +-------+

이제 우리는 때문에 문제가이 Lion모두를 먹을 수 Deer하고 Grass있지만, Deer되지 Food그 것이다 Animal.

다중 상속을 사용하지 않고 객체 지향 디자인을 사용하여이 문제를 어떻게 해결합니까?

참고 : http://www.asciiflow.com 을 사용하여 ASCII 다이어그램을 만들었습니다.


14
현실 세계를 모델링하는 것은 일반적으로 조만간 문제입니다. 비행 물고기, 물고기 또는 새와 같은 이상한 일이 항상 있기 때문입니다. 그러나 펭귄은 새이며 날 수 없으며 물고기를 먹을 수 없습니다). @Ampt가 말하는 것처럼 그럴듯하게 들리면 동물은 먹는 물건을 모아야합니다.
Rob van der Veer

2
동물은 음식에서 물려 받아야한다고 생각합니다. 무언가가 사자를 먹으려 고하면 InvalidOperationException을 던지십시오.
RalphChapin

4
@RalphChapin : 모든 종류의 것들이 사자 (독수리, 벌레 등)를 먹습니다. 나는 동물과 음식이 충분히 넓지 않기 때문에 분해되는 인공적인 구별이라고 생각합니다 (모든 동물은 결국 다른 동물의 음식입니다). "LivingThing"을 분류한다면 살아 있지 않은 것들 (미네랄 등)을 먹는 식물의 경우를 처리해야하며 LivingThing.Eat (LivingThing)을 갖는 것은 아무것도 깨지 않을 것입니다.
Satanicpuppy

2
연구 결과를 공유하면 모든 사람에게 도움이됩니다. 당신이 무엇을 시도했고 왜 그것이 당신의 요구를 충족시키지 못했는지 알려주십시오. 이것은 당신이 시간을내어 자신을 돕기 위해 노력했고, 명백한 답변을 되풀이하는 것을 막아 주며, 무엇보다도보다 구체적이고 적절한 답변을 얻는 데 도움이됩니다. 또한 묻는 방법
gnat

9
이 질문은 Age of Empire III 게임에 의해 답변되었습니다. ageofempires.wikia.com/wiki/List_of_Animals 사슴과 가젤 구현 IHuntable, 양과 암소는 IHerdable(인간에 의해 제어 가능) 사자는 IAnimal 만 구현하며, 이는 그러한 인터페이스를 암시하지 않습니다. AOE3는 instanceof프로그램이 기능을 쿼리 할 수 ​​있도록 특정 개체 (와 유사한)에서 지원하는 인터페이스 집합 쿼리를 지원 합니다.
rwong

답변:


38

IS 관계 = 상속

사자는 동물입니다

A 관계 = 구성

차에 바퀴가있다

CAN DO 관계 = 인터페이스

ICanEat


5
+1 그것은 매우 간단하지만 3 가지 다른 관계 유형에 대한 훌륭한 요약입니다
dreza

4
대안 : ICanBeEaten또는IEdible
Mike Weller

2
CAN HAZ 관계 = lolcats
Steven A. Lowe

1
이 질문에 어떻게 대답합니까?
user253751

13

OO는 실제 세계를 뒤덮는 은유 일뿐입니다. 그러나 은유는 지금까지만 진행되었습니다.

일반적으로 OO에서 무언가를 모델링하는 올바른 방법은 없습니다. 특정 도메인 의 특정 문제대해 올바른 방법이 있으며 도메인 개체가 동일하더라도 문제를 변경하더라도 문제가 해결 될 것으로 기 대해서는 안됩니다.

나는 이것이 대부분의 Comp에 대한 일반적인 오해라고 생각합니다. 영어 학생들은 첫 해에 있습니다. OO는 보편적 인 솔루션이 아니며, 도메인을 합리적으로 잘 모델링 할 수있는 일종의 문제에 대한 적절한 도구 일뿐입니다.

도메인 정보가 없기 때문에 질문에 대답하지 않았습니다. 그러나 위의 사항을 염두에두고 필요에 맞는 것을 설계 할 수 있습니다.


3
+1 OO는 종교가 아닌 도구입니다.
mouviciel

이 문제가 계속 변화하고 발전한다면 완벽한 해결책이 없을 수도 있습니다. 현재 상태 에서이 문제에 도메인 정보가 부족하여 솔루션을 만들 수 있습니까?
Michael Irey

OP에서 실제 세계가 모델링되고 있다고 진지하게 생각하십니까? 관계 모델은 예제를 통해 표시됩니다.
Basilevs

@Basilevs 동물이 실제 생활에서 어떻게 행동하는지 언급하기 때문에 실제로 그 의미가 있습니다. 프로그램 IMO에서 그 행동을 설명해야하는 이유에 대해 관심을 가져야합니다. 즉, 가능한 디자인을 제안하는 것이 좋을 것입니다.
DPM

10

동물을 하위 클래스로 더 세분화하고 싶거나 (적어도 내가하는 일에 합당한 한) 기본 동물과 두 가지 유형의 음식 (식물 및 육류)으로 작업하는 경우 육식 동물과 초식 동물을 사용하여 동물을 더 정의하고 분리 할 수 ​​있습니다. 여기 내가 당신을 위해 만든 것입니다.

             +----------------+                   +--------------------+
             |    Animal      |                   |      Food          |
             |----------------|<--+Interfaces+--->|--------------------|
             |                |                   |                    |
             +----------------+                   +--------------------+
                +           +                       +                 +
                |           |    Abstract Classes   |                 |
                |           |        |          |   |                 |
                v           v        v          v   v                 v
   +-----------------+  +----------------+     +------------+      +------------+
   |   Herbivore     |  |  Carnivore     |     |   Plant    |      |   Meat     |
   |-----------------|  |----------------|     |------------|      |------------|
   |Eat(Plant p)     |  |Eat(Meat m)     |     |            |      |            |
   |                 |  |                |     |            |      |            |
   +-----------------+  +----------------+     +------------+      +------------+
            +                    +                    +                   +
            |                    |                    |                   |
            v                    v                    v                   v
   +-----------------+  +----------------+     +------------+      +------------+
   |  Deer           |  |   Lion         |     |  Grass     |      |  DeerMeat  |
   |-----------------|  |----------------|     |------------|      |------------|
   |DeerMeat Die()      |void Kill(Deer) |     |            |      |            |
   +-----------------+  +----------------+     +------------+      +------------+
                                 ^                    ^
                                 |                    |
                                 |                    |
                              Concrete Classes -------+

보시다시피, 그들은 모두 먹는 방법을 노출하지만 먹는 음식은 변화합니다. 사자는 이제 사슴을 죽일 수 있고, 사슴은 죽고 사슴 고기를 반환 할 수 있으며, 사자가 사슴을 먹을 수는 있지만 풀은 허용하지 않는 방법에 대한 원래의 질문은 전체 생태계를 설계하지 않고도 대답 할 수 있습니다.

물론 사슴은 고기의 한 유형으로 간주 될 수 있기 때문에 매우 흥미 롭습니다. 그러나 간단하게 유지하려면 사슴 아래에 kill ()이라는 메소드를 작성하여 사슴 고기를 반환하고 그것을 콘크리트 클래스 확장 고기.


그러면 사슴이 IMeat 인터페이스를 공개할까요?
Dan Pichelman

육류는 인터페이스가 아니며 추상 클래스입니다. 내가 당신을 위해 그것을 구현하는 방법을 추가
Ampt

Eat(Plant p)그리고 Eat(Meat m)모두 LSP를 위반.
Tulains Córdova

어떻게 @ user61852? 나는 각 유형의 동물이 자체 먹는 방법을 가질 수 있도록 동물 인터페이스에 Eat를 노출시키지 않았습니다.
Ampt

1
TCWL (너무 복잡하고 누출 됨). 문제가 분산되고 발생하며 솔루션은 정적이고 중앙 집중식이며 사전 정의되어 있습니다. TCWL.
Tulains Córdova

7

내 디자인은 다음과 같습니다.

  1. 음식은 인터페이스로 선언됩니다. IMFood와 IVegetable에는 IFood 인터페이스와 두 가지 파생 인터페이스가 있습니다.
  2. 동물은 IMeat를 구현하고 야채는 IVegetable을 구현
  3. 동물은 육식 동물과 육식 동물의 두 자손이 있습니다.
  4. 육식 동물은 IMeat의 인스턴스를받는 Eat 메소드를 가지고 있습니다
  5. 초식 동물에는 IVegetable의 인스턴스를받는 Eat 메소드가 있습니다.
  6. 사자는 육식 동물에서 내려
  7. 초식 동물의 사슴
  8. 잔디는 야채에서 내려

동물은 IMeat를 구현하고 사슴은 (허비 보어) 동물이기 때문에 IMeat를 먹을 수있는 (동물) 동물 인 Lion도 사슴을 먹을 수 있습니다.

사슴은 초식 동물이므로 IVegetable을 구현하기 때문에 Grass를 먹을 수 있습니다.

육식 동물은 IVegeable을 먹을 수 없으며 초식 동물은 IMeat를 먹을 수 없습니다.


1
상속되는 유형이 아무것도 구현하지 않을 때를 제한하기 위해 상속을 사용하여 많은 열거 유형을보고 있습니다 ... 전혀 기능을 구현하지 않는 유형을 만들 때마다, 그것은 발자국입니다. 코드의 유용성에 아무런 가치가없는 타입 시스템에서 모델을 확장했습니다
Jimmy Hoffa

인간, 유인원, 곰과 같은 잡식 동물보다 존재한다는 것을 기억하십시오.
Tulains Córdova

사자와 사슴은 모두 포유류라고 어떻게 덧붙입니까? :-)
johannes

2
@JimmyHoffa "마커 인터페이스"라고하며 인터페이스를 완전히 유효하게 사용합니다. 사용이 정당한지 여부를 결정하려면 코드를 검토해야하지만 많은 사용 사례가 있습니다 (예 : 잔디를 먹는 사자가 NoInterface 예외를 던지는 경우). 마커 인터페이스 (또는 부족)는 지원되지 않는 인수로 메소드가 호출 된 경우 발생하는 예외를 예측하는 역할을합니다.
rwong

1
@ rwong 나는 그 개념을 이해하고 전에 공식화 된 것을 들어 본 적이 없다. 내 경험은 내가 작업 한 코드베이스가 매번 더 복잡하고 유지 관리하기가 어려워졌습니다. 아마도 내 경험은 사람들이 잘못 사용했던 곳 일 것입니다.
지미 호파

5

동물이 먹을 수있는 음식은 실제로 계층 구조를 형성하지 않습니다.이 경우 자연은 간단한 객체 지향 모델링을 준수 할 수 없었습니다.

동물이 먹을 있는 음식에 대한 지식은 어느 수업과도 함께 살 수 없으므로 음식 계층 구조의 일부 구성원을 참조하는 것만으로는 먹을 수있는 음식을 말하기에 충분하지 않습니다.

다 대 다 관계입니다. 즉, 동물을 추가 할 때마다 먹을 수있는 음식을 찾아야하고 음식을 추가 할 때마다 먹을 수있는 음식을 찾아야합니다. 활용할 구조가 더 있는지 여부는 모델링하는 동물과 음식에 따라 다릅니다.

다중 상속은 실제로 이것을 잘 해결하지 못합니다. 동물이 먹을 수있는 음식이나 음식을 먹을 수있는 동물이 필요합니다.


그들이 정규식에 대해 말하는 것처럼 "나는 정규식을 사용했기 때문에 이제 두 가지 문제가 있습니다", MI는 "문제가있어서 MI를 사용했기 때문에 이제 99 개의 문제가 있습니다"라는 문구를 따릅니다. d 먹을 수있는 음식을 알고 있지만 여기에서 찌르는 헛된 것을 따르십시오. 이것은 실제로 모형을 아주 간단하게 만듭니다. 의존성 역전 FTW.
Jimmy Hoffa

1

나는 다른 측면에서 문제에 접근 할 것이다 : OOP는 행동에 관한 것이다. 귀하의 경우, Grass자녀의 행동이 Food있습니까? 따라서 귀하의 경우에는 Grass수업이 없거나 적어도 상속되지 않습니다 Food. 또한 컴파일 타임에 먹을 수있는 사람을 강제 해야하는 경우 Animal추상화 가 필요한지 의심 스럽습니다. 또한 육식 동물풀을 먹는 육식 동물 을 볼 수 있지만 드물지 않습니다.

그래서 나는 이것을 ASCI 예술에 귀찮게하지 않을 것입니다 :

IEdibleType고기, 식물, 시체 등의 열거 형인 property 가있는 경우 (자주 변경되지 않으며 특정 동작이 없으므로 클래스 계층 구조로 모델링 할 필요가 없습니다).

Animal논리적 인 메소드 CanEat(IEdible food)Eat(IEdible food). 그런 다음 특정 동물은 주어진 상황에서 주어진 음식을 먹을 수있을 때마다 확인하고 그 음식을 먹어 생계를 유지하고 다른 것을 할 수 있습니다. 또한 동물 계층 구조의 일부보다 육식 동물, 초식 동물, 잡식 동물을 전략 패턴 으로 모델링 합니다.


1

TL; DR : 상황에 맞는 디자인 또는 모델.

귀하의 질문은 해결하려는 실제 문제의 맥락이 없기 때문에 어렵다고 생각합니다. 일부 모델과 관계가 있지만 작동해야하는 프레임 워크가 부족합니다. 문맥이 없으면 모델링과 은유가 제대로 작동하지 않아 여러 해석에 문이 열려 있습니다.

데이터 소비 방식에 집중하는 것이 더 생산적이라고 생각합니다. 데이터 사용 패턴이 있으면 모델 및 관계가 무엇인지 역으로 쉽게 작업 할 수 있습니다.

예를 들어보다 자세한 요구 사항은 다른 객체 관계를 필요로합니다.

  • 닮지 Animals eat않은 지원FoodGastroliths
  • 지원 Chocolate으로 Poison대한 Dogs,하지만하지 않는Humans

제시된 간단한 관계를 모델링하는 방법에 대한 연습을 시작하면 Food Interface가 가장 좋습니다. 그리고 그것이 총계라면 시스템의 관계가 당신의 벌금입니다. 그러나 몇 가지 추가 요구 사항 또는 관계 만 있으면 더 간단한 경우에 작동 한 모델 및 관계에 크게 영향을 줄 수 있습니다.


나는 동의하지만 그것의 작은 예는 세상을 모델링하려고하지 않았다. 예를 들어 타이어와 번호판을 먹는 상어가있을 수 있습니다. 모든 종류의 객체를 먹는 메소드를 사용하여 부모 추상 클래스를 만들 수 있으며 Food는이 abstact 클래스를 확장 할 수 있습니다.
hagensoft

@hagensoft : 동의합니다. 데이터가 소비되고 사용되는 방법을 보지 않고 개발자가 즉시 파악한 은유를 기반으로 개발자가 모델링하는 것을 끊임없이 볼 수 있기 때문에 때때로 쫓겨납니다. 초기 아이디어를 바탕으로 OO 디자인과 결혼 한 다음 솔루션을 문제에 맞추는 대신 솔루션에 맞게 문제를 강제로 시도합니다.
dietbuddha

1

ECS 구성 오버 상속 방식 :

An entity is a collection of components.
Systems process entities through their components.

Lion has claws and fangs as weapons.
Lion has meat as food.
Lion has a hunger for meat.
Lion has an affinity towards other lions.

Deer has antlers and hooves as weapons.
Deer has meat as food.
Deer has a hunger for plants.

Grass has plant as food.

의사 코드 :

lion = new Entity("Lion")
lion.put(new Claws)
lion.put(new Fangs)
lion.put(new Meat)
lion.put(new MeatHunger)
lion.put(new Affinity("Lion"))

deer = new Entity("Deer")
deer.put(new Antlers)
deer.put(new Hooves)
deer.put(new PlantHunger)

grass = new Entity("Grass")
grass.put(new Plant)

Naturesystem이러한 엔터티를 반복하여 일반화 된 쿼리 함수를 통해 어떤 구성 요소가 있는지 확인합니다. Nature고기에 굶주림을 가진 개체는 무기를 사용하여 음식으로 고기를 가진 다른 개체를 공격합니다. 공격이 성공하면, 개체는 희생자를 먹일 것이고,이 시점에서 희생자는 고기가없는 시체로 변할 것이다. Nature식물에게 기아가있는 개체는 식물이 존재하는 경우 식물을 음식으로하는 개체를 먹일 수 있습니다.

Nature({lion, deer, grass})

Nature(entities)
{
    for each entity in entities:
    {
       if entity.has("MeatHunger"):
           attack_meat(entity, entities.with("Meat", exclude = entity))
       if entity.has("PlantHunger"):
           eat_plants(entity, entites.with("Plant", exclude = entity))
    }
}

아마도 우리 Grass는 햇빛과 물이 필요 하도록 확장하고 싶을 것이며 , 세상에 햇빛과 물을 소개하고 싶을 것입니다. 그러나 Grass이것들은 가지고 있지 않기 때문에 직접 찾을 수 없습니다 mobility. Animals물이 필요할 수도 있지만mobility . 새로운 구성 요소를 추가하고 시스템 (또는 시스템 수)의 동작을 확장하기 때문에 전체 설계의 계단식 손상없이이 모델을 계속 확장하고 변경하는 것은 매우 쉽습니다.


0

다중 상속을 사용하지 않고 객체 지향 디자인을 사용하여이 문제를 어떻게 해결합니까?

대부분의 것들과 마찬가지로, 그것은 달려 있습니다.

그것은 무엇에 달려있다 '이 문제'가 수 있습니다.

  • 그건 일반적으로 구현 문제 , 예를 들어 어떻게 선택한 플랫폼에서 다중 상속의 부재 '를 돌아 다니기'이란?
  • 디자인 문제 입니까 만이 특정 케이스는 , 예를 들어 어떻게 동물은 또한 음식이라는 사실을 모델링하기 위해?
  • 그건 예를 들어 '식품'과 '동물'이 구상 된 실제 적용에 대해 유효하고, 필요하며, 충분한 분류 와 같은 도메인 모델에 철학적 문제 입니까?

일반적인 구현 문제에 대해 묻는다면 환경의 기능에 따라 대답이 달라집니다. IFood 및 IAnimal 인터페이스는 작동 할 수 있으며 EdibleAnimal 서브 클래스는 두 인터페이스를 모두 구현합니다. 환경이 인터페이스를 지원하지 않는 경우 Animal을 Food에서 상속 받으십시오.

이 특정 디자인 문제에 대해 묻는다면 Animal을 Food에서 상속 받도록 만드십시오. 작동 할 수있는 가장 간단한 것입니다.

이러한 설계 개념에 대해 질문하는 경우 모델로 수행하려는 작업에 따라 대답이 달라집니다. 개 먹는 개 비디오 게임이나 심지어 동물원에서 먹이 일정을 추적하는 응용 프로그램이라면 충분할 것입니다. 동물 행동 패턴에 대한 개념적 모델이라면 아마도 다소 얕은 것 같습니다.


0

상속은 항상 다른 것이므로 변경할 수없는 것에 사용해야합니다. 잔디는 항상 음식이 아닙니다. 예를 들어, 나는 풀을 먹지 않습니다.

잔디 특정 동물의 식품 역할 을합니다.


그것은 단지 추상화입니다. 그것이 요구 사항이라면 Plant 추상 클래스를 확장하고 인간이 구체적인 클래스로 먹는 식물을 그룹화하는 'HumanEatablePlants'와 같은 추상 클래스를 먹도록 만들 수 있습니다.
hagensoft

0

당신은 OO의 기본 한계를 만났습니다.

OO는 계층 구조와 잘 작동합니다. 그러나 엄격한 계층 구조에서 벗어나면 추상화가 제대로 작동하지 않습니다.

나는 이러한 한계를 극복하는 데 사용되는 변성 구성 등에 대해 모두 알고 있지만 서투르고 더 중요하게 코드를 모호하게 따르기 어렵습니다.

관계형 데이터베이스는 주로 엄격한 계층 구조의 한계에서 벗어나기 위해 발명되었습니다.

예를 들어 잔디는 건축 자재, 종이의 원료, 의복 재료, 잡초 또는 작물 일 수 있습니다.

사슴은 애완 동물, 가축, 동물원 동물 또는 보호 종일 수 있습니다.

사자는 동물원 동물이나 보호 종일 수도 있습니다.

인생은 간단하지 않습니다.


0

다중 상속을 사용하지 않고 객체 지향 디자인을 사용하여이 문제를 어떻게 해결합니까?

무슨 문제? 이 시스템은 무엇을합니까?대답 할 때까지 어떤 수업이 필요할지 모르겠습니다. 육식 동물과 초식 동물 및 식물을 사용하여 생태학을 모델링하려고 노력하고 있습니까? 컴퓨터가 20 개의 질문을하도록하려고합니까?

사용 사례가 정의되기 전에 설계를 시작하는 것은 시간 낭비입니다. 나는 약 10 명의 팀이 사진을 통해 소프트웨어를 사용하여 항공사의 OO 모델을 생산하기 시작했을 때이 말이 엄청나게 극단적 인 것을 보았습니다. 그들은 실제 비즈니스 문제를 염두에두고 2 년간 모델링 작업을 수행했습니다. 결국 고객은 기다리는 데 지 쳤고 팀에게 실제 문제를 해결하도록 요청했습니다. 이 모든 모델링은 완전히 쓸모가 없었습니다.

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