Каков правильный дизайн OO для максимального повторного использования и эффективности?

#java #oop #inheritance

#java #ооп #наследование

Вопрос:

Предположим, у меня есть пакет Java (оба .jar и исходные коды). Вот определения того, какие некоторые классы я хотел бы использовать повторно.

 abstract class Tree {
  public abstract Tree[] children();
  public void print();
}

class LabeledTree extends Tree implements Label {
  Label label;
  Tree[] daughterChildren;
  public Tree[] children();
}

class Demo {
  public static void main(String[] args) {
    Parser p = new Parser();
    String[] sent = { "This", "is", "an", "easy", "sentence", "." };
    Tree parse = p.apply(sent);
    parse.print();
  }
}
  

apply Метод, описанный выше, возвращает LabeledTree . Теперь я хотел бы создать свой собственный тип дерева, скажем MyTree , который имеет следующую структуру.

 class MyTree {
  int value;
  Label label;
  public void myPrint();
}
  

Где, по вашему мнению, я должен поместить этот класс в дереве наследования, чтобы я мог напрямую создавать экземпляры объектов этого класса из apply метода? Как, по-вашему, я должен проектировать свою систему таким образом, чтобы максимально использовать программное обеспечение повторно и не приходилось анализировать каждое дерево для построения объектов MyTree ?

Ответ №1:

Несколько комментариев:

Прежде всего, ваше определение дерева раскрывает важную деталь — каждый объект дерева является узлом. Это создает целую кучу концептуальных единиц. В реальном API у вас был бы древовидный интерфейс и реализация, использующая узлы. Все элементы данных будут находиться в узле, за исключением корневого узла, который будет находиться в вашем TreeImpl.

Во-вторых, я твердо верю в то, что присвоение имен является важнейшим первым шагом к созданию хорошего и читаемого кода и что это часто влияет на качество вашего дизайна OO. Дерево не должно просто реализовывать label. Можете ли вы сказать: «Дерево — это метка»? С другой стороны, если бы у вас было что-то вроде: «TreeNode реализует HasLabel», было бы понятнее — «ваш узел дерева имеет метку».

В-третьих, вы сталкиваетесь с хорошо известными проблемами ООП соответствия и дисперсии. При вашем текущем дизайне ваш корень помеченного дерева имеет метку, но нижние узлы (которые являются просто деревьями) не обязательно должны быть помеченным деревом. Это было бы забавно отлаживать. Дженерики могут помочь вам решить эту проблему, но обязательно ознакомьтесь с эффективной Java, чтобы понять, как работают ограничивающие универсальные типы.

Ответ №2:

Я согласен с @Uri в том, что создание Tree интерфейсом вместо абстрактного класса было бы улучшением.

Если ваш анализатор не знает о подклассах Tree, то одним из способов является схема, основанная на отражении, с использованием Class.forName. Другим способом справиться с этим было бы использовать систему, в которой расширения регистрируются при их установке (примером здесь является реестр плагинов Eclipse, хотя это очень сложный пример этого шаблона).

Ваш главный вопрос на самом деле о том, как наилучшим образом организовать синтаксические анализаторы, написанные на языке OO. Существует много, очень много книг на эту тему. Вы могли бы попробовать ознакомиться с этой книгой:

Процессоры языка программирования Java: компиляторы и интерпретаторы Дэвид Уотт (автор), Дерик Браун (автор)

Он доступен на Amazon и полезен для начала понимания того, как разрабатывать анализаторы языка. Все примеры приведены на Java.

Кроме того, если у вас есть грамматика, вы могли бы попробовать запустить ее через Antlr и посмотреть на вывод хороших примеров того, как организовать синтаксический анализатор.

http://www.antlr.org/

Ответ №3:

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

Комментарии:

1. Каких элементов не хватает? Не могли бы вы, пожалуйста, более конкретно рассказать об обобщении? Я бы предпочел не трогать код пакета и просто добавить свой собственный.