Будет ли синтаксис композиции полезным дополнением к Java?

Во-первых, я почти ничего не знаю о теории языка, и я почти не знаю никаких других языков, кроме Java, но у меня была идея, которая, на мой взгляд, была бы крутой, но мне нужно, чтобы вы, ребята, сказали мне:
а: почему это отстой b: как язык x имел это в течение многих лет
c: как мой разум отстой d: все вышеперечисленное

Идея придаст композиции такую ​​же простоту повторного использования кода, что и extends.

Итак, если у вас был такой класс:

public interface A {  
    public void methodInA();  
}

А потом у вас был такой класс:

public class B {  
    private composed A;
    public B() {
        // construct A within constructor
    }
}

Тогда вы сможете сделать это:

B myB = new B();
myB.methodInA();

Без необходимости добавлять делегацию в класс B. Но вы также можете сделать то же самое, что и с наследованием, то есть:

@Overrides
public void methodInA(){
    // B's own delegation method
}

К недостаткам можно отнести:

  • методы скрыты в исходном коде, что делает менее очевидным, откуда исходит вызов, но это также относится к extends
  • если составные поля имеют одну и ту же сигнатуру метода, необходимо разрешить конфликт (как конфликтующие интерфейсы решают эту проблему?)
  • если вы хотите иметь несколько составных полей одного и того же типа, возникнет очевидный конфликт, какое поле делегировать
  • возможно еще 100 вещей, о которых я не думал

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

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
4
0
514
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Я не уверен, что вижу в этом явное преимущество. Я понимаю, о чем вы говорите. В настоящий момент для вызова метода на A у вас есть myB.getAInstance (). MethodInA (), но вы хотите сделать это myB.methodInA ().

Но что произойдет, если у вас будет несколько экземпляров A? Как будет разрешен вызов метода? Часто композиция подразумевает связь один-ко-многим, поэтому B имеет много экземпляров A. Что тогда происходит?

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

Это не совсем то, что мне нужно myB.getAInstance (). MethodInA (), я могу использовать составное поле для реализации интерфейса, поэтому у класса должен быть сам метод.

Grundlefleck 31.10.2008 22:49

Звучит круто, но я думаю, что это создает ужасные языковые конструкции. Очевидно, возникает проблема, если вы объявляете более одной «композиции» одного и того же класса, но даже если вы запрещаете это, как насчет случая, когда вызов соответствует методу более чем в одном из (разных) составных классов? Вам нужно будет указать, какой из них был вызван в основном классе, и для этого вам понадобится дополнительный синтаксис. Ситуация становится еще хуже, если в классах есть публичные члены.

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

«... Я думаю, что это вряд ли когда-нибудь будет представлено в Java». - Я слышал, что, если я смогу сформировать идею дополнения к одному из, если не самому, широко используемому языку программирования, в этот довольно медленный день ... ну, у нас с Sun проблемы :-D

Grundlefleck 31.10.2008 23:09

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

Grundlefleck 31.10.2008 23:21

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

  • Подходит ли для сборки мусора весь граф объектов или только его заголовок?

Пара инструментов сопоставления ORM и фреймворков над ними или вокруг них обеспечивают отношения belongsTo или has-many между постоянными объектами, а некоторые также обеспечивают каскадное удаление (для композиции). Я не знаю ни одного свободного предложения, которое предоставляет простой синтаксический сахар, который вы ищете.

На самом деле, если задуматься, идиомы Groovy MetaClass и MetaProgramming могут предоставить нечто очень похожее с «автоматическим магическим» делегированием.

Множественное наследование разрешено в C++, я знаю, что по-разному, но это один и тот же мыслительный процесс. Java была разработана так, чтобы не допускать множественного наследования, чтобы было меньше путаницы, а следовательно, ошибок и эксплойтов.

То, что вы предложили, прямо противоречит принципам java.

Сказав это, это было бы круто (не обязательно полезно). Я программист на Java, перешедший с C++. Мне нравится делать собственные ошибки.

Ознакомьтесь с тем, что называется «миксинами» на некоторых языках и «ролями» в системе Perl 5 Moose OO.

Ответ принят как подходящий

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

Лично я ненавижу наследование конкретных классов. Я большой сторонник пункта 14 из статьи Блоха Эффективная Java, Предпочитайте композицию наследованию. Я думаю, что что-то подобное упростит реализацию идиомы, которую он рекомендует в этом пункте.

Честно говоря, если бы вы действительно знали, что делаете, держу пари, вы могли бы написать аннотацию компилятора, которая справилась бы с этим. Итак, если у вас есть класс Bar, в котором реализован интерфейс IBar, ваш класс будет выглядеть так:

public class Foo {

  @Delegate(IBar.class)
  private Bar bar;

  // initialize bar via constructor or setter
}

Затем во время компиляции Foo можно было бы заставить реализовать IBar, и любой из методов в этом интерфейсе, которые еще не были реализованы Foo, в конечном итоге будет сгенерирован следующим образом:

public Baz method1(Qux val) {
  return bar.method1(val);
}

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

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

«Честно говоря, если бы ты действительно знал, что делаешь ...» - и в этом вся загвоздка, мой друг! :-D

Grundlefleck 31.10.2008 22:54

Подход, который я бы предпочел, состоял бы в том, чтобы позволить классу назначать двух членов (например, first и second), чтобы попытка доступа к foo.someMemberName, когда у foo нет такого члена, переписывалась бы как foo.first().someMemberName [без попытки рекурсивного поиска при возврате из first], а в случае неудачи - foo.first().someMemberName [разрешающий рекурсивный поиск при возврате из second]. Обратите внимание, что никакого «наложения» рекурсивных поисков не потребуется.

supercat 14.05.2015 23:16

Другие вопросы по теме