Comments 8
Самопальная реализация правильного ООП в JS? Кажется, в этом месяце ещё не было.
Когда я был молод и горяч, у меня частенько возникало желание исправить несправедливость в мире программирования и реализовать недостающую функциональность там, где, как мне казалось, ей самое место, ведь она так прекрасно работает в другом языке/контексте/начальных условиях. Но со временем я подрос и понял, что всему свое место. Как, знаете, в поговорке «нафига козе баян?». Подходы, которые замечательно работают в ООП с настоящими классами, не факт, что нужны при прототипном наследовании, и наоборот. Более того, каждый раз читая статью про попытку приблизить JS к языкам, в которых честное ООП закладывалось в архитектуру языка изначально, или в которой в JS пытаются добавить то, что там совсем не нужно просто потому, что в JS уже есть все инструменты для решения той же самой задачи, но по-другому, и глядя на ту сложность кода, с помощью которого это все предлагается реализовать, я в очередной раз убеждаюсь в своей правоте. Не нужно в JS эмулировать защищенные методы) А в вашей реализации это еще и вредно, потому как добавляет необоснованной сложности в полезный код и накладные расходы при выполнении.
> проще понимать работу класса и находить в нем ошибки. (Сразу видно в каких case'ах используются члены класса. Если приватные — то анализировать надо только данный класс, ну, а если защищенные — то только данный и производные классы.)
Чтобы проще понимать работу класса, не стоит использовать длинные цепочки наследования и стараться делать взаимодействие между классами как можно яснее. Также можно использовать композицию вместо наследования. Еще вариант — принять на уровне code convention, что все свойства, которые начинаются с нижнего подчеркивания (_) — защищенные. Это поможет еще и визуально упростить понимание, как можно использовать метод/свойство при одном только взгляде на его имя. И все это без той сложности, которую добавляет ваша реализация.
> легче управлять изменениями. (Например, можно убирать приватные члены, не опасаясь, что сломается что-то вовне редактируемого класса.)
Приватные члены — это хорошо) Они вполне себе нормально реализуются средствами языка через замыкание. Как этот пункт описывает преимущества защищенных методов именно в вашей реализации, не совсем понятно.
> уменьшается количество заявок в bug-трекере, т.к. пользователи библиотеки или контрола могут «зашиться» на наши «приватные» члены, которые в новой версии класса мы решили убрать, либо изменить логику их работы.
Чтобы такого не было, обычно пишут документацию для внешних пользователей, в которой как раз и описывается API библиотеки/контрола/etc, которые можно использовать. Все остальное — нельзя, потому как может поменяться. Ну а имена свойств с нижнего подчеркивания помогут выделить различие еще и визуально.
Еще обычно на каждый баг в трэкере пишут сценарий воспроизведения, из которого часто понятно, что и где использовали и почему оно так могло получиться. Там же сразу и станет ясно, использовали ли недокументированные функции.
> И в целом, защищенные члены класса — это инструмент проектирования. Хорошо иметь его под рукой отлаженным и хорошо протестированным.
Согласен, но если это реализовано и поддерживается на уровне языка, с соответствующими оптимизациями в нативном коде и с минимальными накладными расходами при выполнении. Но в вашем случае это только добавляет сложности в реальном коде и нагрузки при его выполнении.
> проще понимать работу класса и находить в нем ошибки. (Сразу видно в каких case'ах используются члены класса. Если приватные — то анализировать надо только данный класс, ну, а если защищенные — то только данный и производные классы.)
Чтобы проще понимать работу класса, не стоит использовать длинные цепочки наследования и стараться делать взаимодействие между классами как можно яснее. Также можно использовать композицию вместо наследования. Еще вариант — принять на уровне code convention, что все свойства, которые начинаются с нижнего подчеркивания (_) — защищенные. Это поможет еще и визуально упростить понимание, как можно использовать метод/свойство при одном только взгляде на его имя. И все это без той сложности, которую добавляет ваша реализация.
> легче управлять изменениями. (Например, можно убирать приватные члены, не опасаясь, что сломается что-то вовне редактируемого класса.)
Приватные члены — это хорошо) Они вполне себе нормально реализуются средствами языка через замыкание. Как этот пункт описывает преимущества защищенных методов именно в вашей реализации, не совсем понятно.
> уменьшается количество заявок в bug-трекере, т.к. пользователи библиотеки или контрола могут «зашиться» на наши «приватные» члены, которые в новой версии класса мы решили убрать, либо изменить логику их работы.
Чтобы такого не было, обычно пишут документацию для внешних пользователей, в которой как раз и описывается API библиотеки/контрола/etc, которые можно использовать. Все остальное — нельзя, потому как может поменяться. Ну а имена свойств с нижнего подчеркивания помогут выделить различие еще и визуально.
Еще обычно на каждый баг в трэкере пишут сценарий воспроизведения, из которого часто понятно, что и где использовали и почему оно так могло получиться. Там же сразу и станет ясно, использовали ли недокументированные функции.
> И в целом, защищенные члены класса — это инструмент проектирования. Хорошо иметь его под рукой отлаженным и хорошо протестированным.
Согласен, но если это реализовано и поддерживается на уровне языка, с соответствующими оптимизациями в нативном коде и с минимальными накладными расходами при выполнении. Но в вашем случае это только добавляет сложности в реальном коде и нагрузки при его выполнении.
UFO just landed and posted this here
Я уж было думал что высокое искусство накостылить Очередные Единственные Труъ Классы в JS отомрёт с выходом и повсеместным распространением ES6/2015 и повсеместным же распространением TypeScript и .d.ts. — ан нет, жив курилка. И двух недель не прошло с обсуждения пропозала о приватных свойствах...
Ну да, подумаешь замедлили создание объектов на порядок, зато отладка созданных таким образом объектов будет увлекательной.
Нужно начинать с того что любая попытка реализации аспектов ООП в JS есть костыль.
Из долгих дебатов на тему нужны ли в классах члены с protected-доступом мне показалось разумным аргумент, что вместо того, чтобы разделять приватные члены с производными классами (а ведь protected-доступ, по сути, именно это и означает), нужно создавать новые классы и использовать композицию. И эти новые классы, можно было бы разделять между производными классами.
т.е. вместо
разумно сделать
т.е. вместо
function Base(){
//@protected как бы делаем метод защищенным и разделяем его с производными классами
function protectedMethod(){}
}
разумно сделать
function SomeSpeciaFunctionality(){
this.method = function (){ // useful code
}
}
function Base(){
var _compositionInstance = new SomeSpeciaFunctionality();
function myPrivateFunction(){
_compositionInstance.method();
}
}
function DerivedClass(){
var _compositionInstance = new SomeSpeciaFunctionality();
function anotherPrivateFunction(){
_compositionInstance.method();
}
}
Однако не всегда получается красиво так выделить функционал в отдельный класс. Иногда, бывает так, что приватный метод, который нужно сделать protected сильно завязан на члены класса Base.
И ладно еще если метод зависит от публичных членов класса Base, тогда можно было бы вызывать метод в контексте Base, таким образом
хуже, когда защищаемый метод зависит от приватных, т.е. замкнутых членов класса Base.
Хотя и это не смертельно, можно отказаться от реализации приватных членов через замыкание и использовать замкнутый приватный контекст и на нем уже вызывать:
И ладно еще если метод зависит от публичных членов класса Base, тогда можно было бы вызывать метод в контексте Base, таким образом
function SomeSpeciaFunctionality(){
this.method = function (){ // useful code
}
}
function Base(){
var _self = this;
var _compositionInstance = new SomeSpeciaFunctionality();
function myPrivateFunction(){
_compositionInstance.method.call(_self);
}
}
хуже, когда защищаемый метод зависит от приватных, т.е. замкнутых членов класса Base.
Хотя и это не смертельно, можно отказаться от реализации приватных членов через замыкание и использовать замкнутый приватный контекст и на нем уже вызывать:
function SomeSpeciaFunctionality(privateMembers){
this.method = function (){ // useful code
}
}
function Base(){
var _self = this;
var _privateMembers ={
myPrivateVariable: 12
}
var _compositionInstance = new SomeSpeciaFunctionality(_privateMembers);
function myPrivateFunction(){
_compositionInstance.method.call(_self);
}
}
Sign up to leave a comment.
Protected методы в JavaScript ES5