Множественное наследование в Python; как это сделать в Java? - PullRequest
1 голос
/ 31 декабря 2010

Я портирую некоторый код Python на Java, и у меня возникают проблемы при решении следующей проблемы:

У меня есть несколько классов, которые должны иметь способности A, B или C. Классу 1 нужна способность A, классу 2 нужны A, B и C, а классу 3 нужны B и C. Самое главное, я хочу легко быть в состоянии изменить, какой класс может иметь какие способности в будущем.

Я решил эту проблему довольно легко с множественным наследованием в Python. Я пытаюсь найти лучший способ сделать это на Java, но я не могу придумать такого хорошего решения. Я знаю, что множественное наследование осуждается, поэтому я был бы признателен, если бы меня учили лучше.

Спасибо!

Ответы [ 8 ]

3 голосов
/ 31 декабря 2010

Это зависит от вашего фактического варианта использования, но вы уже рассматривали декораторы?

http://en.wikipedia.org/wiki/Decorator_pattern

3 голосов
/ 31 декабря 2010

Множественное наследование не осуждается. Не одобряется «наследование реализации» (также известное как «повторное использование кода»), потому что оно приводит к неразрешимой «проблеме алмазов». И потому, что повторное использование кода на самом деле не имеет ничего общего с ОО.

То, что вы хотите сделать, может быть решено с помощью множественного наследования (и, скажем, делегирования, если вам нужно выполнить «повторное использование кода»).

interface A {

    void move();

}

interface B {

    void eat();

}

interface C {

    void think();

}

class One implements A { ... }

class Two implements B { ... }

class Three implements B, C { ... }

Любой OOA / OOD, использующий множественное наследование, может быть тривиально переведен на Java. Часть, в которой вы говорите, что вам нужно все время менять «способность», немного страшна: если, скажем, Car может move(), зачем ему вдруг понадобится think()?

1 голос
/ 31 декабря 2010

Множественное наследование - почти всегда плохая идея, так как его эффекты обычно могут быть достигнуты с помощью других механизмов. Исходя из вашего описания проблемы, звучит так, как будто вы хотите

  1. Использование интерфейсов для определения поведения (открытый интерфейс A) в этом сценарии, каждое поведение, вероятно, должно иметь свой собственный интерфейс.

Если 2 поведения тесно связаны (скажем, A & B), определите интерфейс, который реализует эти два атомарных интерфейса (открытый интерфейс CombinedAandB расширяет A, B)

  1. Определите абстрактный базовый класс, который реализует интерфейс, чтобы обеспечить реализации по умолчанию для поведения

    public abstract class BaseAB implements A, B
    {
       @Override 
       public void A() { add(0,1); }
    
    
    <pre><code>   @Override
       public void B() {add(1,0); }
    
    
       private void add(int a, int b) //it doesn't return. no soup for you.
       { a + b; //If you know why this is wrong, high five yourself. }
    
    }
  2. Определите конкретный класс, который расширяет абстрактный базовый класс, реализует другой интерфейс и обеспечивает его собственное поведение.

    открытый класс IDoABAndC расширяет BaseAB, реализует C { // прочее }

1 голос
/ 31 декабря 2010

Вы можете довольно просто использовать синтаксис mixin AspectJ для эмуляции множественного наследования (и во время компиляции тоже). Сначала объявите интерфейс для функций, которые вы хотите смешать:

public interface A{
    String getSomethingForA();
}

затем определите аннотацию, которую вы можете использовать, чтобы указать, что вы хотите, чтобы миксин применялся к данному классу:

public @interface WithA {}

затем добавьте аннотацию к классу, который вы хотите использовать:

@WithA
public class MyClass {}

затем, чтобы добавить некоторые функции:

@Aspect
public class MixinA {
    public static class AImpl implements A{
        public String getSomethingForA() {
            return "it worked!";
        } 
    }

    @DeclareMixin("@WithA *")
    public static A get() {
        return new AImpl();
    }
}

Вам нужно будет использовать jar aspectj и запускать аспекты как часть процесса компиляции, но это позволит вам создать действительно модульную функциональность и затем принудительно объединить ее с вашими классами. Чтобы получить доступ к вашему классу с новой функциональностью, выполните следующие действия:

MyClass obj = new MyClass();
((A)obj).getSomethingForA();

Вы можете применить ту же аннотацию к другому классу, а также разыграть ее:

@WithA
@WithB //let's pretend we created this with some other functionality
public class AnotherClass {}

AnotherClass anotherObj = new AnotherClass();
((A)anotherObj).getSomethingForA();
((B)anotherObj).andSetSomethingElseForB("something else");
0 голосов
/ 31 декабря 2010

Это немного тангенциально, но вы можете иметь код Python, работающий на Java через Jython (http://www.jython.org/). Это относится к переносу на Java-часть, а не к решению проблемы множественного наследования (я думаю, вам нужно определить, какая из них актуальна)

0 голосов
/ 31 декабря 2010

Если вам нужно интерфейс наследование, то, как упоминалось ранее, вы всегда можете реализовать несколько интерфейсов.

Если вы ищете реализацию наследования, вам не повезло. Лучшее решение, вероятно, состоит в том, чтобы использовать делегирование - заменить дополнительные суперклассы полями и реализовать методы, которые просто делегируют эти поля. Это требует написания большого количества повторяющихся методов делегирования, но это довольно неизбежно в Java (не прибегая к AspectJ или другим приемам манипулирования байт-кодом;

0 голосов
/ 31 декабря 2010

В Java у вас нет множественного наследования, вместо этого вы можете реализовать несколько интерфейсов.

Таким образом, ваш класс 1 будет реализовывать интерфейс A и B. Класс 2 будет реализовывать интерфейс A, B и C. Класс 3будет осуществлять B и C.

0 голосов
/ 31 декабря 2010

Вы можете определить способности в интерфейсах и реализовать их в своих классах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...