2012-01-28 3 views
3

Я знаю, что Java не поддерживает множественное наследование. Но если мне нужно разработать систему классов, скажем, Королевство животных. Как представлять животных, которые являются гибридами двух разных животных? Например, Мул (Осел или Лошадь?), Лигер (Лев или Тигр). Как наследовать классы Lion и Tiger, чтобы сделать класс Liger? Есть ли способ сделать это, не делая Тигра и Льва в качестве интерфейсов? Что делать, если они не могут быть сделаны интерфейсами?Проектирование иерархии классов - множественное наследование в Java

ответ

8

Наследование не является подходящим инструментом для использования в этом случае. Видите ли, лигером является не тигр, и ни один из них не является львом. Это имеет характеристики обоих, но это is.

Скажите, что вы идете в зоопарк, и клетка говорит «Тигр». Вы заглядываете и видите эту странную гигантскую кошку, которую вы, конечно, не узнаете как тигр. It's cool, но не тигр. Вы тоже не думаете, что это лев. Это не substitutable для обоих.

Таким образом, он должен составить в Lion и Tiger и делегат свое поведение к правой, или «переопределение» их поведение полностью или частично.

UPDATE:

Теперь, что делать, если вы действительно хотите какой-то множественное наследование, например, если вы хотите вывести Liger как с Hybrid и Feline? Взгляните на Scala traits. Чтобы реализовать его на Java, вам понадобится интерфейс и класс для каждой концепции в дизайне, которую вы хотите размножить «наследовать». Взгляните на идею here.

+1

+1. ИМО, это лучший ответ. –

+1

Хорошее объяснение! Теперь гораздо понятнее, как обрабатывать такие сценарии. Я не очень хорошо знаком с делегацией и композиционными концепциями, но определенно буду вникать и учиться. Спасибо за вашу помощь. – Periastron

0

Как вы упомянули, это невозможно. Плюс это также может быть признаком плохого дизайна (поскольку это может привести к двусмысленности, даже если это было возможно). Таким образом, вам, возможно, придется попытаться избежать этого и переосмыслить свой дизайн.

+0

Независимо от того, вызывает ли оно двусмысленность, зависит от того, что подклассы. –

+0

ИМХО, в случае с Лигером, это, скорее всего, принесет двусмысленность. –

+1

Конечно, но это всегда зависит от того, что является подклассом, и поведения классов. Я хотел сказать, что это признак плохого дизайна - это радикальное обобщение, которое, как я считаю, не может быть надежно подтверждено. –

6

Они всегда должны быть интерфейсами iff. Вы хотите, чтобы один объект можно было идентифицировать как оба.

Вы можете часто делегировать поведение в композитные классы, но в случае с liger (это в значительной степени мой любимый подкласс) вам нужно решить, какое поведение животного будет иметь приоритет. Лигер может быть прямым потомком того или другого, или нет.

Java допускает множественное «наследование API» (интерфейсы), а не реализацию.

0

Java не поддерживает множественное наследование классов. Рассмотрим функции, которые могут иметь общие слова «Лев» и «Тигр». Java не захотела решить проблему «столкновения функций»:

class Lion{ 
    public String call(){ 
     return "ROAR"; 
    } 
} 
class Tiger{ 
    public String call(){ 
     return "growl"; 
    } 
} 
class Liger extends Lion, Tiger{ 
} 

public static void main(String[] args){ 
    System.out.println(new Liger().call()); 
} 

Что должно быть напечатано?

Java не поддерживает множественное наследование классов, поэтому это не сработает - часть расширений Lion, Tiger объявления класса является незаконной. Java поддерживает механизм устранения неоднозначности для интерфейсов, но это не распространяется на классы.

Ваш лучший выбор - конвертировать каждые класс животных в интерфейс, а затем преобразовать код в реализации этих интерфейсов. Лигер может быть реализован следующим образом:

interface Liger extends Lion, Tiger { } 
class LigerImpl implements Liger{ 
    private Lion mom; 
    private Tiger dad; 
    public LigerImpl(){ 
     mom = new LionImpl(); 
     dad = new TigerImpl(); 
    } 
    public String call(){ 
     if(math.random() > 0.5){ 
      return mom.call(); 
     } else { 
      return dad.call(); 
    } 
} 

Этот подход требует явного делегирования каждой из базовых реализаций; абсолютно ничего не происходит «бесплатно». Однако Java не приблизит вас. Дизайн Java в значительной степени сводится к «если что-либо в чем-то неоднозначно, небезопасно, неопределенно или потенциально может вызвать конфликт типа или разбора, заставьте программиста написать больше кода».

0

Я NOT Рекомендуем вам сделать это, но отражение может работать. Конечно, использование «instanceof» никогда не будет работать ...

public class Lion { 
    public void roar() { 
     System.out.println("Lion is roaring"); 
    } 

    public void eat(String what) { 
     System.out.println("Lion is eating " + what); 
    } 
} 

public class Tiger { 
    public void purr() { 
     System.out.println("Tiger is purring"); 
    } 

    public void eat(String what) { 
     System.out.println("Tiger is eating " + what); 
    } 
} 

import java.lang.reflect.Method; 
import java.util.ArrayList; 


public class Liger { 
    public static void main(String[] args) { 
     Liger liger = new Liger(); 
     liger.purr(); 
     liger.roar(); 
     liger.eat("food"); 

     //Result 
     //Tiger is purring 
     //Lion is roaring 
     //Tiger is eating food 
     //Lion is eating food 
    } 

    private ArrayList<Object> _extends = new ArrayList<Object>(); 

    public Liger() { 
     _extends.add(new Tiger()); 
     _extends.add(new Lion()); 
    } 

    private void invoke(String methodName, Object... args) { 
     for (Object obj : _extends) { 
      Class cls = obj.getClass(); 
      Method[] methods = cls.getMethods(); 
      for (Method m : methods) { 
       if (m.getName().equals(methodName)) { 
        try { 
         m.invoke(obj, args); 
        } 
        catch (Exception ex) { 
         //handle me 
        } 
        continue; 
       } 
      } 
     } 
    } 

    public void purr() { 
     invoke("purr"); //Tiger only 
    } 

    public void roar() { 
     invoke("roar"); // Lion only 
    } 

    public void eat(String what) { 
     invoke("eat", what); //Both 
    } 
} 
+0

Это просто уродливый, ненадежный способ делегирования. –

+0

Ах да .. это неоспоримо страшно, однако это «бы» работа. –

Смежные вопросы