Во-первых, я почти ничего не знаю о теории языка, и я почти не знаю никаких других языков, кроме 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Как я уже сказал, я явно не теоретик языка, и я давно не думал об этом, эта идея просто пришла мне в голову, и я хотел знать, насколько я ошибаюсь. Я просто думаю, что это было бы круто.




Я не уверен, что вижу в этом явное преимущество. Я понимаю, о чем вы говорите. В настоящий момент для вызова метода на A у вас есть myB.getAInstance (). MethodInA (), но вы хотите сделать это myB.methodInA ().
Но что произойдет, если у вас будет несколько экземпляров A? Как будет разрешен вызов метода? Часто композиция подразумевает связь один-ко-многим, поэтому B имеет много экземпляров A. Что тогда происходит?
Я согласен с перечисленными вами недостатками. Это может просто вызвать слишком много путаницы, чем того стоит.
Звучит круто, но я думаю, что это создает ужасные языковые конструкции. Очевидно, возникает проблема, если вы объявляете более одной «композиции» одного и того же класса, но даже если вы запрещаете это, как насчет случая, когда вызов соответствует методу более чем в одном из (разных) составных классов? Вам нужно будет указать, какой из них был вызван в основном классе, и для этого вам понадобится дополнительный синтаксис. Ситуация становится еще хуже, если в классах есть публичные члены.
Композиция используется для предотвращения проблем с множественным наследованием. Разрешение такой композиции фактически разрешает множественное наследование, по крайней мере, с точки зрения разрешения того, какой метод вызывать. Поскольку ключевым дизайнерским решением для Java было запретить множественное наследование (по уважительным причинам), я думаю, что это вряд ли когда-либо будет введено в Java.
«... Я думаю, что это вряд ли когда-нибудь будет представлено в Java». - Я слышал, что, если я смогу сформировать идею дополнения к одному из, если не самому, широко используемому языку программирования, в этот довольно медленный день ... ну, у нас с Sun проблемы :-D
Как насчет того, если компилятор обнаружит конфликт, он заставит вас отменить его? Таким образом, вы вынуждены разрешить это одним-единственным способом, без особых затрат на синтаксис, поскольку это не выглядело бы неуместным. Но общественные деятели ... да, вообще о них не думали ... хммм.
Также следует учитывать разницу между состав и агрегирование. Как компилятор узнает, имеете ли вы в виду отношения «есть» или «имеет»?
Пара инструментов сопоставления 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
Подход, который я бы предпочел, состоял бы в том, чтобы позволить классу назначать двух членов (например, first и second), чтобы попытка доступа к foo.someMemberName, когда у foo нет такого члена, переписывалась бы как foo.first().someMemberName [без попытки рекурсивного поиска при возврате из first], а в случае неудачи - foo.first().someMemberName [разрешающий рекурсивный поиск при возврате из second]. Обратите внимание, что никакого «наложения» рекурсивных поисков не потребуется.
Это не совсем то, что мне нужно myB.getAInstance (). MethodInA (), я могу использовать составное поле для реализации интерфейса, поэтому у класса должен быть сам метод.