Вопросы проектирования множественного наследования в Java

Как Вы имеете дело с наличием только единичного наследования в Java? Вот моя определенная проблема:

У меня есть три (упрощенных) класса:

public abstract class AbstractWord{
    String kind;    // eg noun, verb, etc

    public String getKind(){ return kind; }

}

public class Word extends AbstractWord{
    public final String word;

    ctor...

    public void setKind(){
        // based on the variable word calculate kind..
    }
}

public class WordDescriptor extends AbstractWord{

    ctor..

    public void setKind(String kind){this.kind = kind;}

}

Это - то, что я рассматриваю своим наиболее базовым внедрением, но я хочу сделать другие реализации.

Позволяет говорят, что я хочу добавить, что новая переменная говорит, что wordLength, но я хочу добавить его с помощью наследования. Значение, которое я НЕ хочу, изменяет тот исходный класс AbstractWord. Т.е. что-то вроде этого:

public class Length{
    private int length;

    public int getLength(){return length};
}

public class BetterWord extends AbstractWord AND Length{

    public void setLength(){
        // based on the variable word calculate Length..
    }
}

public class BetterWordDescriptor extends AbstractWord AND length{

    public void setLength(int length){this.length = length;}
}

Я знаю, что Java не позволяет мне сделать это, но он сделал мой код очень ужасным. Прямо сейчас каждый раз, когда я добавляю поле, я просто добавляю его к AbstractWord, но затем я любой должен переименовать тот AbstractWord (и Word и WordDescriptor). (Я не могу только добавить поле к другому из-за назад совместимости, это повреждается, равняется методам и материалу как этот).

Это походит на проблему довольно общего умысла, но я установил голову в стойку, и я не могу предложить красивые решения.

Существует ли шаблон разработки, который обращается к этому? У меня есть некоторые потенциальные решения, но я хотел видеть, было ли что-то, что я пропускал.

спасибо, Jake

Обновление: Длина относится к количеству слогов в слове (извините об отсутствии ясности)

8
задан sixtyfootersdude 27 January 2010 в 03:58
поделиться

6 ответов

о пользу состава на наследство.

Решение учитывает, что может быть другой тип слова, который может понадобиться WordLengeSupport.

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

.

public class WordLength {
    private int length = 0;
    public int getLength(){return length};
    public void setLength(int length){this.length = length};
}

.

public interface WordLengthSupport {
    public WordLength getWordLength();
}

.

public class BetterWord extends AbstractWord 
        implements WordLengthSupport {
    WordLength wordLength;
    public WordLength getWordLength() {
        if(wordLength==null) {
            // each time word changes 
            // make sure to set wordLength to null
            calculateWordLength(); 
        }
        return wordLength;
    }
    private void calculateWordLength() {
        // This method should be 
        //    called in constructor 
        //    or each time word changes 
        int length = // based on the variable word calculate Length..
        this.wordLength = new WordLength();
        this.wordLength.setLength(length);
    }
}

.

public class BetterWordDescriptor extends AbstractWord  
        implements WordLengthSupport {
    WordLength wordLength;
    public WordLength getWordLength(return wordLength);
    public void setWordLength(WordLength wordLength) {
        // Use this to populate WordLength of respective word
        this.wordLength = wordLength;
    }
}

.

Узор стратегии определения семейства алгоритмов, инкапсулирует каждый и делает их взаимозаменяемыми. Стратегия позволяет алгоритму варьироваться независимо от клиентов, которые его используют.

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

9
ответ дан 5 December 2019 в 10:41
поделиться

С вашим конкретным примером вы можете использовать образец Decorator в сочетании с интерфейсами для дополнения вашего класса класса с дополнительными функциями; например

// *Optional* interface, useful if we wish to reference Words along with
// other classes that support the concept of "length".
public interface Length {
  int getLength();
}

// Decorator class that wraps another Word and provides additional
// functionality.  Could add any additional fields here too.
public class WordExt extends AbstractWord implements Length {
  private final Word word;

  public class(Word word) {
    this.word = word;
  }

  public int getLength() {
    return word.getKind().length();
  }
}

Кроме того, стоит отметить, что отсутствие многократного наследования в Java на самом деле не проблема здесь; Это больше случай для переработки вашего дизайна. В целом это считается плохим практикой в ​​чрезмерное использование наследство как глубокие иерархии наследования трудно интерпретировать / поддерживать.

-121--3603184-

(Я не могу просто добавить поле на другой из-за обратной совместимости, он сломается равна методам и такому так).

Это не сломает совместимость источника. Нет, если вы не делаете что-то действительно сумасшедшее в ваших методах равных.

И переименование ваших классов, как правило, не способ обрабатывать двоичную совместимость.

0
ответ дан 5 December 2019 в 10:41
поделиться

В вашем конкретном примере вы можете использовать шаблон декоратора в сочетании с интерфейсами, чтобы дополнить ваш класс Word дополнительными функциональными возможностями; например,

// *Optional* interface, useful if we wish to reference Words along with
// other classes that support the concept of "length".
public interface Length {
  int getLength();
}

// Decorator class that wraps another Word and provides additional
// functionality.  Could add any additional fields here too.
public class WordExt extends AbstractWord implements Length {
  private final Word word;

  public class(Word word) {
    this.word = word;
  }

  public int getLength() {
    return word.getKind().length();
  }
}

Кроме того, стоит отметить, что отсутствие множественного наследования в Java на самом деле не является здесь проблемой; это скорее случай переделки вашего дизайна. В целом считается плохой практикой чрезмерное использование наследования, так как глубокие иерархии наследования трудно интерпретировать/сохранять.

2
ответ дан 5 December 2019 в 10:41
поделиться

Глядя на него, мое первое чувство состоит в том, что ваша модель немного сложная.

Слово имеет строку для описания самого слова, которое хранится в словом объекте вместе с классом, чтобы сказать, что это существительное, глагол, прилагательное и т. Д. Еще одно свойство слова - это длина строки, хранящейся в слове объект.

Подумайте о вещах в отношениях «IS-A» и «есть-a», и вы можете удалить много сложности.

Например, почему вам нужен WordDescriptor, который расширяет абстрактное слово? Это слово, перейдя с глагола к прилагательному? Я бы подумал, что тип слов был установлен, когда объект был создан, и не изменится в течение срока службы объекта слова. Как только у вас было слово «объект» для слова «Австралия», то слово не изменится на всю жизнь объекта.

Хммм. Может быть, у вас может быть слово объект, представляющий слово «кору» после создания объекта с типом «глагола», чтобы описать звук, который делает собаку. Затем вы понимаете, что на самом деле нужно иметь слово объект для представляющих существительное, которое описывает покрытие дерева. Возможно, но оба коры собаки могут существовать кору дерева.

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

Начните, задавая себе вопрос для каждого из аспектов наследования вашей основной модели.

Когда я говорю, что класс B расширяет класс A, могу ли я сказать, что класс B "IS-A" класс A и что я специализируюсь на его поведение?

Например, животное базового класса может быть расширено для обеспечения специализированного Класс кенгуру. Тогда вы можете сказать, что «кенгуру» - это «животное». Вы специализируетесь на поведении.

Затем посмотрите на атрибуты, Kangaroo имеет атрибут местоположения для описания, где он найден. Тогда вы можете сказать кенгуру ». У «местонахождения». Кангару «IS-A» местоположение не имеет смысла.

Аналогично, слово «имеет-a» длина. И оператор слова «- это» длина просто не делает Смысл.

BTW Все австралийские ссылки в этом посте являются преднамеренными, чтобы отпраздновать день Австралии, который сегодня 26 января!

HTH

2
ответ дан 5 December 2019 в 10:41
поделиться

Проблема не «как иметь дело с одним наследством». То, что вам не хватает, - это не на самом деле шаблон дизайна, но учится разработать API отдельно от реализации.

Я бы реализовал его так:

public interface WordDescriptor {
    void getKind();
    Word getWord();
}

public interface Word {
    String getWord();
}

public class SimpleWord implements Word {
    private String word;

    public SimpleWord(String word) { this.word = word; }
    public String getWord() { return word; }
}

public class SimpleWordDescriptor implements WordDescriptor {
    private Word word;
    private String kind;

    public SimpleWordDescriptor(Word word, String kind) {
        this.word = word;
        this.kind = kind; // even better if WordDescriptor can figure it out internally
    }

    public Word getWord() { return word; }

    public String getKind() { return kind; }
}

с этой основной настройкой, когда вы хотите ввести свойство длины, все, что вам нужно сделать, это:

public interface LengthDescriptor {
    int getLength();
}

public class BetterWordDescriptor extends SimpleWordDescriptor
                                  implements LengthDescriptor {
    public BetterWordDescriptor(Word word, String kind) {
        super(word, kind);
    }

    public int getLength() { getWord().length(); }        
}

Другие ответы, которые используют состав свойств, а также Декоратор-рисунок также являются совершенно действующими решениями вашей проблемы. Вам просто нужно определить, какие ваши объекты есть и как «композитируемые» они и как они должны использоваться, - отсюда сначала разработает API.

0
ответ дан 5 December 2019 в 10:41
поделиться

Просто используйте композицию вместо наследования:

A Breatword IS-AN Абстрактное слово , что имеет длину :

public class BetterWord extends AbstractWord {

    private Length length;

    public void setLength(int value){
        length.setLength(value);
    }
}

редактировать

Если API нуждается в объекте длины типа, просто добавьте Getter:

public class BetterWord extends AbstractWord {

    private Length length;

    public void setLength(int value){
        length.setLength(value);
    }

    public Length getLength() {
        return length
    }
}

или переименовать реализацию Длина - Длина и определить интерфейс Длина , потому что класс может реализовать несколько интерфейсов.

3
ответ дан 5 December 2019 в 10:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: