Здравствуйте, WFrag, Вы писали:
WF>Здравствуйте, antonlavreev, Вы писали:
A>>Добрый день, A>> я все-таки никак не пойму почему у "профессиональных" разработчиков ПО часто прослеживается паранойя наследования — надо что-то заимплементить, мы пронаследуемся и еще раз и еще.... Может стоит остановиться и подумать над дизайном??? Ведь неоправданное наследование это тупиковый вариант, для последующего внесения изменений, они нарастают как снежный ком...
WF>Да, иной раз смотришь на то, что понаписали джуниоры, и понимаешь, что порой наследование — это как копипаст, но без копипаста
[skipped] ЖМ>Как считает цивилизованная общественность, идея полного отказа от наследования в пользу делегирования — имеет ли право на существование?
Имеет, только это крайне непрактично. Во-первых, если вы бездумно замените вертикальный граф наследования на горизональный граф композиции объектов, система станет абсолютно нечитаемой начинающими программистами. Во-вторых, это, конечно, мизер, да и не столь важно по сравнению с гибкостью системы, тем не менее будет падение производительности системы.
Здравствуйте, igna, Вы писали:
R>>... статически детерминировано; I>Это что?
Наследование класса определяется статически на этапе компиляции кода, в отличие от композиции, которая определяется только во время исполнения откомпилированного кода.
I>http://en.wikipedia.org/wiki/Statically_indeterminate?
Очень смешно.
Здравствуйте, rsn81, Вы писали:
R>Наследование класса определяется статически на этапе компиляции кода, в отличие от композиции, которая определяется только во время исполнения откомпилированного кода.
В Java по умолчанию все вызовы виртуальные. Разве что при композиции вызов будет скорее всего через интерфейс, что медленнее просто виртуального вызова. Но в обоих случаях Hotspot может соптимизировать виртуальный вызов обычным, если посчитает нужным.
Здравствуйте, rsn81, Вы писали:
R>Наследование класса определяется статически на этапе компиляции кода, в отличие от композиции, которая определяется только во время исполнения откомпилированного кода.
Это утверждение и для C++ верно? (Хочу понять, что имеется ввиду.)
Вот композиция:
class A
{
};
class B
{
A a;
};
Та ли это композиция, "которая определяется только во время исполнения откомпилированного кода"?
Здравствуйте, igna, Вы писали:
I>Та ли это композиция, "которая определяется только во время исполнения откомпилированного кода"?
Надо полагать, имелась в виду динамическая композиция:
class B
{
A* _a;
public: B(A* a) { _a = a; }
}
Хотя скорее "полудинамическая":
class B
{
A& _a;
public: B(A& a): _a(a){}
}
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Надо полагать, имелась в виду динамическая композиция:
Надо, больше не остается ничего. Но с тогда этот плюс наследования по сравнению с композицией отпадает. Используй статическую или там "статически детерминированную" композицию, вот и все. Единственный остающийся плюс это то, что наследование "проще в использовании, так как вшито в ООЯ". Тут он прав, наследование "вшили" очень хорошо, и не только в ООЯ.
Здравствуйте, igna, Вы писали:
I>Надо, больше не остается ничего. Но с тогда этот плюс наследования по сравнению с композицией отпадает.
Дабы не гадать далее, вы вместо чтения Wiki-заборов откройте уже книгу GoF, а конкретно в главе "Механизмы повторного использования" два параграфа: "Наследование и композиция" и "Сравнение структур времени выполнения и времени компиляции".
I>Используй статическую или там "статически детерминированную" композицию, вот и все.
Вы пока не догоняете, что есть композиция, а потому сказали какой-то бред, уж извините.
I>Единственный остающийся плюс это то, что наследование "проще в использовании, так как вшито в ООЯ". Тут он прав, наследование "вшили" очень хорошо, и не только в ООЯ.
Попытка №2. Есть две абсолютно (!) различных структуры в ООП:
времени компиляции: фиксируется на этапе компиляции, так отношение наследования между классами неизменно;
времени выполнения: представляет собой постоянно меняющийся граф взаимодействующих объектов во время исполнения, так отношение владения ссылкой на объект (отношения агрегирования или осведомленности) определяется в динамике и по определению может быть изменено.
Фишка в том, что за первую структуру обычно отвечает язык (компилятор), а вот за вторую всецело проектировщик (в управляемых платформах компилятор, конечно, пытается и даже некоторые нехорошие вещи, которые могут случится во время исполнения, предсказывает, но все же компиляторы пока до телепатических способностей проектировщиков не доросли) — чем более он опытный, тем более лаконичная структура объектов первого вида, а потому чуть меньше работы компилятору, тем более сложная вторая структура, то есть мозги работают на полную.
Здравствуйте, rsn81, Вы писали:
R>Попытка №2. Есть две абсолютно (!) различных структуры в ООП:
R>времени компиляции: фиксируется на этапе компиляции, так отношение наследования между классами неизменно;
Для той же Java это в общем случае не верно. При компиляции у тебя может быть один SomeSuperClass класс, а при выполнении окажется совсем другой. Более того, он даже по методам/полям может быть местами не совместим.
R>времени выполнения: представляет собой постоянно меняющийся граф взаимодействующих объектов во время исполнения, так отношение владения ссылкой на объект (отношения агрегирования или осведомленности) определяется в динамике и по определению может быть изменено.Фишка в том, что за первую структуру обычно отвечает язык (компилятор), а вот за вторую всецело проектировщик (в управляемых платформах компилятор, конечно, пытается и даже некоторые нехорошие вещи, которые могут случится во время исполнения, предсказывает, но все же компиляторы пока до телепатических способностей проектировщиков не доросли) — чем более он опытный, тем более лаконичная структура объектов первого вида, а потому чуть меньше работы компилятору, тем более сложная вторая структура, то есть мозги работают на полную.
Тут тоже не всё так просто. Очень часто композиция фиксируется однажды (например, IoC контейнером при запуске приложения) и не меняется во время работы.
Здравствуйте, rsn81, Вы писали:
R>Наследование класса определяется статически на этапе компиляции кода, в отличие от композиции, которая определяется только во время исполнения откомпилированного кода.
Слово "только" здесь лишнее. Фразу "Object composition is defined dynamically at run-time through objects acquiring references to other objects" (GoF) следует понимать как "Динамически композиция объектов определяется посредством получения ссылок на другие объекты". Что вовсе не означает будто композиция не может определяться статически.
Здравствуйте, WFrag, Вы писали:
WF>Для той же Java это в общем случае не верно. При компиляции у тебя может быть один SomeSuperClass класс, а при выполнении окажется совсем другой. Более того, он даже по методам/полям может быть местами не совместим.
Совсем не понял, разжуйте.
WF>Тут тоже не всё так просто. Очень часто композиция фиксируется однажды (например, IoC контейнером при запуске приложения) и не меняется во время работы.
Фиксация времени выполнения — это выполнение процессором некоторого набора команд. Фиксация времени компилирования — это фиксация состава этого набора команд. Разницу совсем не видите, да?
Здравствуйте, igna, Вы писали:
I>Слово "только" здесь лишнее. Фразу "Object composition is defined dynamically at run-time through objects acquiring references to other objects" (GoF) следует понимать как "Динамически композиция объектов определяется посредством получения ссылок на другие объекты". Что вовсе не означает будто композиция не может определяться статически.
Означает. При наследовании время жизни предка и потомка совпадают, соответственно, когда мы уже в контексте обсуждения возможностей потомка (рассматриваем время строго после завершения конструктора) автоматически подразумевается, что родитель тоже существует — это и есть фиксация (есть один объект <=> есть другой объект). А при композиции время жизни объектов не совпадает, в общем случае, в особенности если забыть о GC, вообще никак не связано, а значит, что пока один объект (уже существующий) не получит ссылку на другой объект, он (первый) не может сделать никаких предположений о существовании или нет второго — он попросту не имеет к тому никаких возможностей. Таким образом, говорить здесь какой-то "статической фиксации" является словоблудием.
Здравствуйте, rsn81, Вы писали:
R>А при композиции время жизни объектов не совпадает, в общем случае, в особенности если забыть о GC, вообще никак не связано, а значит, что пока один объект (уже существующий) не получит ссылку на другой объект, он (первый) не может сделать никаких предположений о существовании или нет второго — он попросту не имеет к тому никаких возможностей. Таким образом, говорить здесь какой-то "статической фиксации" является словоблудием.
[skipped] I>Это композиция или нет?
Перечитайте определение композиции (особенно внимательно — концовку), которые вы сами же и процитировали здесь: Re[10]: паранойя наследования
Здравствуйте, rsn81, Вы писали:
R>Перечитайте определение композиции (особенно внимательно — концовку), которые вы сами же и процитировали здесь: Re[10]: паранойя наследования
Здравствуйте, antonlavreev, Вы писали:
A>Добрый день, A> я все-таки никак не пойму почему у "профессиональных" разработчиков ПО часто прослеживается паранойя наследования — надо что-то заимплементить, мы пронаследуемся и еще раз и еще.... Может стоит остановиться и подумать над дизайном??? Ведь неоправданное наследование это тупиковый вариант, для последующего внесения изменений, они нарастают как снежный ком...
Ну почему... У меня вот обратная картина: привык мыслить функционально... ОО-решение приходит только во вторую очередь, да и то, хорошенько подумать нужно...
Вот писал интерпретатор виртуальной машины... Сходу написал все на функциях... Основной цикл процессора вызывает нужную функцию по указателю из массива указателей. А код операции является индексом.
А потом только подумал, что можно было определить абстрактный класс Команда и наследоваться от него для реализации каждой команды.
Пока реализовал промежуточное решение: разделил все на 2 дружественных класса: класс-процессор и класс-система команд. Инкапсулировал все функции-команды в класс система-команд как статические. Дальше буду реализовывать нормальный ОО-подход.
Это я опять к топику "что плохого в С++". Сильно много свободы. Одну и ту же работу — в трех разных видах делаю. Правда плюс есть — можно сравнивать подходы на практике. Но это только мне как преподу и пригодиться. А в реальном программировании сравнивать некогда — "копать" надо...
Вот и получается, что в большом проекте каждый пишет как привык, а не так, как нужно...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, rsn81, Вы писали:
R>Не знаю, быть может, такой беглый пример поможет понять
Java к счастью не единственный язык. Возможно в Java наследование и в самом деле имеет тот плюс по сравнению с композицией, что наследование "статически детерминировано", но в других языках "статически детерминированной" может быть и композиция.
Здравствуйте, rsn81, Вы писали:
R>Здравствуйте, WFrag, Вы писали:
WF>>Для той же Java это в общем случае не верно. При компиляции у тебя может быть один SomeSuperClass класс, а при выполнении окажется совсем другой. Более того, он даже по методам/полям может быть местами не совместим. R>Совсем не понял, разжуйте.
Компилируем такие классы:
public class A {
public void doSome() {
System.err.println("A.doSome()");
}
public void doSome2() {
System.err.println("A.doSome2()");
}
}
// Вызываем один метод если параметров не передано, и другой -- если передано.public class B extends A {
public static void main(String[] args) {
B b = new B();
b.invoke(args.length == 0);
}
public void invoke(boolean flag) {
if(flag) {
doSome();
} else {
doSome2();
}
}
}
Потом в отдельном каталоге компилируем такой класс:
public class A {
public void doSome() {
System.err.println("OtherA.doSome()");
}
}
Копируем туда B.class с первого каталога и запускаем:
wfrag@fragentoo ~/1/2 $ java -cp . B
OtherA.doSome()
wfrag@fragentoo ~/1/2 $ java -cp . B some
Exception in thread "main" java.lang.NoSuchMethodError: B.doSome2()V
at B.invoke(B.java:11)
at B.main(B.java:4)
Как видишь, у класса B магически подменился предок безо всяких перекомпиляций, причём у этого предка даже метода одного не хватает.
WF>>Тут тоже не всё так просто. Очень часто композиция фиксируется однажды (например, IoC контейнером при запуске приложения) и не меняется во время работы. R>Фиксация времени выполнения — это выполнение процессором некоторого набора команд. Фиксация времени компилирования — это фиксация состава этого набора команд. Разницу совсем не видите, да?
О какой фиксации идёт речь? Что именно фиксируется-то?
В случае Java по большому счету отличие лишь в том, что в случае наследования вызов некоторого функционала делается на параметре this (неявный параметр при вызове методов), а в случае композиции -- на некотором поле (т.е сначала получаем значение поля, потом делаем вызов).