Denis
То, что базовые методы не будут переопределены (или, скажем так: будут переопределены КОРОЕКТНО) можно гарантировать введя ответственность программиста за КЛАСС. То есть каждый класс -- это зона ответственности того или иного разработчика. Всегда легко понять, кто накосячил. Ну и есть другие плюсы этого плдхода, о которых я не пишу тут. Практика показывает, что коллективная ответственность -- это зло, приводящее к говнокоду (исключение составляют только некоторые экстремальные методики управления процессом разработки типа agile и иже с ним, но в этом случае пролема решается совсем другими методами). А в Вашем случае, один и тот же модуль будет редактироваться РАЗНЫМИ программистами и в случае возникновения проблем они будут спихивать ответственность друг на дружку
Легаси код никто не отменял. Также говнокод обычно появляется потому что надо быстро и сейчас, а тех долг никто не разгреб. Ответственность программиста не гарантирует правильного использования наследования. Да и нет особой разницы кто накосячил, даже если человек еще работает, код в любом случае придется писать тебе, не будешь же ты с ним на ножах драться из-за того что он не так класс написал, особенно когда это уже продакшен код. Без коллективной ответсвенности не обойтись, вдруг человек заболел или в отпуск ушел, а изменения надо делать, неужели вы их отложите? Рано или поздно при любом разделении разные программисты будут хоть и не значительно но править классы друг друга Сомневаюсь что программисты будут спихивать ответсвенность друг на дружку, ну да, они могут по фрустрировать от криво написанного класса или сложного лукового наследования, но они в итоге просто возьмут и сделают задачу.
Maks
Всмысле вот он написал плохой код его уволили))) Вы же не заставите его хорошо написать если он откажется) И это уже уход от темы про композицию и наследование с плюсами первого)
Dmitry
А если программист который написал говнокод в классе ушел и спустя много лет пришел новый?
В идеале каждый класс должен реализовывать конкретный интерфейс, и в логике приложения везде должны использоваться только интерфейсы.
Denis
Если использовался метод персональной ответственности, то говнокода не было. Такое бывает только при коллективной ответственности
При персональной ответственности может быть такое "это мой модуль и я сознательно пишу в нем говнокод, потому что надо быстро и сейчас. Я сознательно потом это поправлю, ведь это моя ЛИЧНАЯ ответственность", а потом такой программист увольняется или уходит в отпуск и его модуль с допущениями обсирается в продакшене и править его начинают те, что сегодня на работе и видят что он там "интересно напрограмировал"
Таршиш
Всмысле вот он написал плохой код его уволили))) Вы же не заставите его хорошо написать если он откажется) И это уже уход от темы про композицию и наследование с плюсами первого)
личная заинтересованность людей и их любовь к деньгам при грамотном руководстве решают все проблемы. Это уже вопрос экономики, а не программировпния
Denis
личная заинтересованность людей и их любовь к деньгам при грамотном руководстве решают все проблемы. Это уже вопрос экономики, а не программировпния
Начальник: сделай фичу Програмист: Чтобы сделать эту фичу понадобится 5 дней Н: Сделаешь сегодня получишь премию П: /* Делает */ На выходе имеем так себе код
Maks
И опять же, это отступление от темы. Наследование ни лучше и не решает никаких проблем
Maks
Даже наоборот, позволяет сделать хуже. Но если говорить про хороший код, то композиция будет лучше
Maks
Так как она более гибкая
Таршиш
При персональной ответственности может быть такое "это мой модуль и я сознательно пишу в нем говнокод, потому что надо быстро и сейчас. Я сознательно потом это поправлю, ведь это моя ЛИЧНАЯ ответственность", а потом такой программист увольняется или уходит в отпуск и его модуль с допущениями обсирается в продакшене и править его начинают те, что сегодня на работе и видят что он там "интересно напрограмировал"
Как раз на оборот: программист пишет говнокод именно потому, что "надо побыстрее" и "все равно буду виноват не я". В случае когда "быстро не получается", программист просто не возьмет задачу, потому что правильно расценивает свои силы. Ну и вообще, ситуация, когда прога сегодня пишется, а завтра используется -- это уже само по себе является признаком кривого руководства (мы не рассматриваем торговые компании, пишущие примочки для каждого товара под каждого дилера). В ситуации, когда программист не рискует взять на себя ответственность, он может заняться написанием _абстрактых_ классов для использования в ближайшем будущем. Но это возможно только при использовании ООП
DI
Добрый день. При запуске go build в каталоге модуля команда ругается на отсутствие файлов в этом каталоге. Подскажите, в чем может быть причина?
Таршиш
Даже наоборот, позволяет сделать хуже. Но если говорить про хороший код, то композиция будет лучше
Ну, учитывая Ваше отношение к ООП, Вам будет только хуже. А процессу производства ПО -- лучше😭
Maks
Ну, учитывая Ваше отношение к ООП, Вам будет только хуже. А процессу производства ПО -- лучше😭
Вы опять путаете ооп и наследование. Я не говорил что ООП это плохо. Я говорил что наследование не обязательный атрибут.
DI
PS D:\programming\go\src\study_go> go build no Go files in D:\programming\go\src\study_go PS D:\programming\go\src\study_go> go env set GO111MODULE= set GOARCH=amd64 set GOBIN= set GOCACHE=C:\Users\idabs\AppData\Local\go-build set GOENV=C:\Users\idabs\AppData\Roaming\go\env set GOEXE=.exe set GOFLAGS= set GOHOSTARCH=amd64 set GOHOSTOS=windows set GOINSECURE= set GOMODCACHE=D:\programming\go\pkg\mod set GONOPROXY= set GONOSUMDB= set GOOS=windows set GOPATH=D:\programming\go\ set GOPRIVATE= set GOPROXY=https://proxy.golang.org,direct set GOROOT=C:\Program Files\Go set GOSUMDB=sum.golang.org set GOTMPDIR= set GOTOOLDIR=C:\Program Files\Go\pkg\tool\windows_amd64 set GOVCS= set GOVERSION=go1.16.6 set GCCGO=gccgo set AR=ar set CC=gcc set CXX=g++ set CGO_ENABLED=1 set GOMOD=D:\programming\go\src\study_go\go.mod set CGO_CFLAGS=-g -O2 set CGO_CPPFLAGS= set CGO_CXXFLAGS=-g -O2 set CGO_FFLAGS=-g -O2 set CGO_LDFLAGS=-g -O2 set PKG_CONFIG=pkg-config set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0 -fdebug-prefix-map=C:\Users\idabs\AppData\Local\Temp\go-build950382669=/tmp/go-build -gno-record-gcc-switches
Denis
Как раз на оборот: программист пишет говнокод именно потому, что "надо побыстрее" и "все равно буду виноват не я". В случае когда "быстро не получается", программист просто не возьмет задачу, потому что правильно расценивает свои силы. Ну и вообще, ситуация, когда прога сегодня пишется, а завтра используется -- это уже само по себе является признаком кривого руководства (мы не рассматриваем торговые компании, пишущие примочки для каждого товара под каждого дилера). В ситуации, когда программист не рискует взять на себя ответственность, он может заняться написанием _абстрактых_ классов для использования в ближайшем будущем. Но это возможно только при использовании ООП
Такая ситуация обычно в любом стартапе, задач много времени мало, а конкруренты уже на рынке и чуть что готовы душить. Но чем композиция хуже наследования то? Предположим что у нас все ок со сроками, хорошее руководство и зрелая компания. Вы ведь знаете как работает встраивание типов в го?
DI
go mod tidy?
PS D:\programming\go\src\study_go> go mod tidy PS D:\programming\go\src\study_go>
Denis
PS D:\programming\go\src\study_go> go mod tidy PS D:\programming\go\src\study_go>
все прости, возможно надо написать так go build .
DI
Точка в конце через пробел
PS D:\programming\go\src\study_go> go build .\src\main.go Работает только так. Файлы в каталоге src находятся, забыл сказать. Но модуль разве не предусматривает это?
Таршиш
Вы опять путаете ооп и наследование. Я не говорил что ООП это плохо. Я говорил что наследование не обязательный атрибут.
Наследование -- это всего один из трех китов ООП. И им надо уметь пользоваться. При необходимости. Я не говорил, что наследование надо втыкать в каждую дырку. Надо просто уметь его использовать. Альтернативой наследованию является агрегация. И если Вы боитесь использовать наследование (вдруг случайно перекрою родительский метод), -- Вы можете принять решение использоват агрегацию. Но при этом и наследование и агрегация подразумевают подход ООП.
DI
А go run . при этом нормально работает?
Точно так же. Ругается на отсутствие. Может какую то переменную нужно прописать, которая указывает, где в модуле находятся файлы?
Dmitry
Таршиш
Такая ситуация обычно в любом стартапе, задач много времени мало, а конкруренты уже на рынке и чуть что готовы душить. Но чем композиция хуже наследования то? Предположим что у нас все ок со сроками, хорошее руководство и зрелая компания. Вы ведь знаете как работает встраивание типов в го?
Композиция -- это аналог агрегации. Если Вы не наследуетесь от родительского кода, а подключаете родительскиц код в виде анрегации, то Вы скрываете от других классов методы родительского класса. Кстати, Вы в курсе, что в си++ есть два типа наследования: публичное и приватное. И, если Вы хотите защититься от несанкционированного переопределения Вашего метода другим программистом -- просто используйте нужный тип наследования!
Denis
Только в основах шарю
С npm работал или с composer? Это пхп или нода
Denis
Нет. Не изучал ноды
Ладно просто для разрабов на ноде/пхп есть чуть более привычный гайд https://github.com/golang-standards/project-layout/blob/master/README_ru.md Но его пока можешь не читать В общем судя по всему твоя ошибка в том что у тебя main.go лежит в src Структура проекта должна быть примерно такая src/ —module1 ——main.go //содержит package main —module2 ——main.go //содержит package main ——blablabla.go —module3 // не исполняемый, просто шарит код ——blablabla.go В папках module1/2 исполняемые модули, т.к. содержат пакет main(файл может называться как угодно не обязательно имя файла должно совпадать с именем пакета) и в этих папках должен корректно отрабатывать go run . если он корректно отрабатывать, то и go build должет также корректно отработать. Папка с модулем3 это просто код, который могут импортировать другие модули, но go run . в нем не сработает, т.к. нет пакета main Если еще не читал эти статьи читай 1 https://golang.org/doc/code 2 https://golang.org/doc/gopath_code Должно стать понятнее. Судя по go env окружение у тебя настроено правильно, просто ты немного намудрил в папке src Когда разберешься с GOPATH можешь разобраться с go mod vendor (ссылка в самом начале этого сообщения)
Denis
Нет. Не изучал ноды
Только я го ланг изучаю 2 дня, и успел всего пару апишек накидать, так что не факт что я прав, но я думаю знающие ребята поправят если что
Таршиш
Ну и кстати я так и не понял кейсов когда наследование необходимо
В большинстве своем оно необходимо. Но, если Вам не нравится, -- используйте агрегацию. В зависимости от Вашей ситуации
Maks
А случай то хоть один будет?)
Таршиш
А случай то хоть один будет?)
Я уже писал про девайс с классом вместо докумментации.
Таршиш
Я уже писал про девайс с классом вместо докумментации.
Продаешь железку вместе с классом. А покупатель наследует от класса...
Таршиш
Продаешь железку вместе с классом. А покупатель наследует от класса...
А еще возьми книжку про DesignPattern: там много примеров наследовпния
Denis
Продаешь железку вместе с классом. А покупатель наследует от класса...
В данном кейсе наследоваться зачем? Можно просто сделать new VendorClass() и все
Таршиш
Denis
Тогда родительские методы перестанут работать.
ЧТо? Всмысле перестанут? Которые protected?
Таршиш
Тогда родительские методы перестанут работать.
Ну Вы же НЕ наследовались от родительского класса! Так с какого перепугу у класса долдны быть методы родителя?
Denis
агрегация classMyClass { private: AnotherClass m_anotherClass; } Вот, примерно так
Я не был знаком с этой фичей, я ведь правильно понял что я могу переопределить protected метод родителя в дочернем классе при private наследовании? Если это так, то инкапсуляция сущностей при агрегации будет выше, т.к. в случае агрегации, будет возможность только декорировать метод родителя, без смены его функциональности родительского метода, т.к. при агрегации мы не можем переоределить метод.
Denis
Ну Вы же НЕ наследовались от родительского класса! Так с какого перепугу у класса долдны быть методы родителя?
Публичные методы. Вы же предоставляете пользователю интерфейс работы с вашим датчиком, его врядли волнуют детали реализации вашего класса и скорее всего его будет интересовать VendorClassInterface, а не VendorClass сам по себе. В плюсах же интерфейсы могут только публичные методы содержать? Я просто на плюсах не программировал
Таршиш
Публичные методы. Вы же предоставляете пользователю интерфейс работы с вашим датчиком, его врядли волнуют детали реализации вашего класса и скорее всего его будет интересовать VendorClassInterface, а не VendorClass сам по себе. В плюсах же интерфейсы могут только публичные методы содержать? Я просто на плюсах не программировал
Меня волнует то, чтобы НЕ НАВРЕДИТЬ. Если я модифицирую некий класс, заменяя в нем наследование агрегацией, то другие модули проекта, работающие с этим классом потеряют возможность вызывать некоторые методы, которые ранее были доступны. Поскольку я НЕ ЕДИНСТВЕННЫЙ программист в компании, а есть еще и другие программисты, я допускаю вероятность того, что новый класс будет вызван из програмы другого программиста и он будет весьма печален, узнав, что его ПО перестало собираться
Denis
Да, но при этом, всё, ранее написанное ПО для родительского класса не сможет использовать все его методы.
Почему же, в вашем классе(постовляемом вместе с датчиком) достаточно сделать публичными те методы которые легально может использовать пользователь.
Maks
Потому что нужно использовать не классы а интерфейсы.
Maks
Вопросы плохого кода не относятся к вопросам наследования или агрегации
Таршиш
Почему же, в вашем классе(постовляемом вместе с датчиком) достаточно сделать публичными те методы которые легально может использовать пользователь.
Зачем? Класс устройства, которое пришло от продавца нельзя модифицировать. Каждый модифицирует на СВОЕМ уровне.
Denis
Зачем? Класс устройства, которое пришло от продавца нельзя модифицировать. Каждый модифицирует на СВОЕМ уровне.
Да, я знаю, его и не надо модифицировать, зачем? У тебя все методы доступны публично, создай инстанс и используй нужные тебе методы, если тебе нужно расширить функционал сделай агрегацию. Зачем в данном случае наследование использовать?
Таршиш
Почему же, в вашем классе(постовляемом вместе с датчиком) достаточно сделать публичными те методы которые легально может использовать пользователь.
Вот видите, Вы говорите "легально использовать". Это означает, что ООП позволяет программисту понять, какие методы являются легальными, а какие -- нет. Это ОРГАНИЗАЮЩИЙ момент. Композиция этого не позволяет; программисты могут вызывать _внутрениие_, методы и вносить путаницу. А ООП проводит точную грань, запрещает другому программисту использовать нечто, что ему запрещено
Таршиш
Просто я подразумивал что при композиции программист может вызвать только публичные методы
Походе, мы разные вещи плдразумеваем под походими именами. Но не будем вдаваться в детали ЯП. ООП поощряет разделения труда между программистам. И это уже много
Maks
при чем тут ООП и разговор о наследовании/композиции??????????????? Почему ты вечно на ООП ссылаешься в обсуждении вообще другой вещи?
Maks
ну мы говорим про композицию/агрегацию против наследования, а ты каждый раз вставляешь ооп, хотя про ооп никто не спорит
Таршиш
почему композиция не позволяет понять какие методы легальны а какие нет, если класс который мы вкладываем композицией нам говорит какие у него методы "легальные"
Вначале кое-кто использовал слово "Композиция" в контексте структур и интерфейсов Go. Но в последниий раз, явно идет речь т какой-то другой композиции. Поэтому давайте для начала определим, что же мы подразумеваем под этим словом
Denis
Нет. Я просто показал разницу между наследованием и агрегацией
Я же правильно понимаю что в этом примере classMyClass { private: AnotherClass m_anotherClass; } у m_anotherClass можно вызвать только публичные методы?
Таршиш
Я же правильно понимаю что в этом примере classMyClass { private: AnotherClass m_anotherClass; } у m_anotherClass можно вызвать только публичные методы?
ИЗВНЕ класса, конечно, можно вызывать только публичные методы. Все методы класса AnotherClass для ИЗВНЕ недоступны. Но они доступны ИЗНУТРИ. Это я показал один из способов, как скрыть от внешних модулей реализацию
Denis
ИЗВНЕ класса, конечно, можно вызывать только публичные методы. Все методы класса AnotherClass для ИЗВНЕ недоступны. Но они доступны ИЗНУТРИ. Это я показал один из способов, как скрыть от внешних модулей реализацию
classMyClass { private: AnotherClass m_anotherClass; void someMethod(){ m_anotherClass.publicMethod() //так можно, правильно? m_anotherClass.privateMethod() //так нельзя m_anotherClass.protectedMethod() //так нельзя } } Я ведь правильно понял это?
Таршиш
Да!
Таршиш
Короче: если программист (который пишет на си++) захочет запретить пользователю делать то или иное действие над его классом (например, запретить наследование, запретить изменение, запретить переопределение) -- он сможет это сделать. Поэтому вопросы типа "А вдруг кто-нибудь по ошибке сделает что-нибудь" вполне решаем административно
Denis
Да!
Агрегация и композиция в данном сообщении одно и тоже, и рассматривает пример кода с classMyClass В таком случае при агрегации легальными являются публичные методы и не раскрываются детали реализации (protected/private), т.к. они недоступны извне А при наследовании, становится возможным править protected/private методы, хотя скорее всего разработчиком класса VendorClass это не подразумевалось, ведь он не просто так объявил их приватными. Потому агрегация проводит четкую границу между двумя классами. Наследование же размывает эту границу, т.к. у тебя есть больше возможностей для смены функционала исходного класса и возможность поменять внутренее устройство работы класса. Таким образом агрегация понижает связность системы и зависимость модулей друг от друга, за счет повышения инкапсуляции. Наследование наоборот повышает связность и зависимость внутри системы. Но это и логично, т.к. агрегация скорее ожидает интерфейс, а наследовение скорее всего происходит от конкретной(например базовой) реализации.
Denis
Короче: если программист (который пишет на си++) захочет запретить пользователю делать то или иное действие над его классом (например, запретить наследование, запретить изменение, запретить переопределение) -- он сможет это сделать. Поэтому вопросы типа "А вдруг кто-нибудь по ошибке сделает что-нибудь" вполне решаем административно
Ну то что запретить он это может понятно. Но суть то не в том может или нет, private/public/protected как раз о том что программист объясняет другому программисту как можно использовать его класс и что в нем можно менять. В контексте vendor классов, которые поставляет нам какая-то компания, логичено предположить что protected/private вмешательству не подлежат и использовать мы можем только публичную область вендорных классов. Ну по крайней мере так пхп, джаве, жс, тайпскрипте, и го ланге, больше ни на чем не писал
Таршиш
Агрегация и композиция в данном сообщении одно и тоже, и рассматривает пример кода с classMyClass В таком случае при агрегации легальными являются публичные методы и не раскрываются детали реализации (protected/private), т.к. они недоступны извне А при наследовании, становится возможным править protected/private методы, хотя скорее всего разработчиком класса VendorClass это не подразумевалось, ведь он не просто так объявил их приватными. Потому агрегация проводит четкую границу между двумя классами. Наследование же размывает эту границу, т.к. у тебя есть больше возможностей для смены функционала исходного класса и возможность поменять внутренее устройство работы класса. Таким образом агрегация понижает связность системы и зависимость модулей друг от друга, за счет повышения инкапсуляции. Наследование наоборот повышает связность и зависимость внутри системы. Но это и логично, т.к. агрегация скорее ожидает интерфейс, а наследовение скорее всего происходит от конкретной(например базовой) реализации.
Допустим, я написал некий класс, а другой программист в СВОЕМ классе переопределил метод МОЕГО класса. Для меня это ровным счетом никакой опасности не представляет. Если переопределение было осуществлено некорректно, то это однозначно будет ошибкой того программиста, кто сделал переопределение. И это он обязательно обнаружит САМ при тестировании! Ведь нельзя де сдавать продукт, не протестировав его!