Как стать автором
Обновить

Комментарии 8

Самопальная реализация правильного ООП в JS? Кажется, в этом месяце ещё не было.
Когда я был молод и горяч, у меня частенько возникало желание исправить несправедливость в мире программирования и реализовать недостающую функциональность там, где, как мне казалось, ей самое место, ведь она так прекрасно работает в другом языке/контексте/начальных условиях. Но со временем я подрос и понял, что всему свое место. Как, знаете, в поговорке «нафига козе баян?». Подходы, которые замечательно работают в ООП с настоящими классами, не факт, что нужны при прототипном наследовании, и наоборот. Более того, каждый раз читая статью про попытку приблизить JS к языкам, в которых честное ООП закладывалось в архитектуру языка изначально, или в которой в JS пытаются добавить то, что там совсем не нужно просто потому, что в JS уже есть все инструменты для решения той же самой задачи, но по-другому, и глядя на ту сложность кода, с помощью которого это все предлагается реализовать, я в очередной раз убеждаюсь в своей правоте. Не нужно в JS эмулировать защищенные методы) А в вашей реализации это еще и вредно, потому как добавляет необоснованной сложности в полезный код и накладные расходы при выполнении.

> проще понимать работу класса и находить в нем ошибки. (Сразу видно в каких case'ах используются члены класса. Если приватные — то анализировать надо только данный класс, ну, а если защищенные — то только данный и производные классы.)

Чтобы проще понимать работу класса, не стоит использовать длинные цепочки наследования и стараться делать взаимодействие между классами как можно яснее. Также можно использовать композицию вместо наследования. Еще вариант — принять на уровне code convention, что все свойства, которые начинаются с нижнего подчеркивания (_) — защищенные. Это поможет еще и визуально упростить понимание, как можно использовать метод/свойство при одном только взгляде на его имя. И все это без той сложности, которую добавляет ваша реализация.

> легче управлять изменениями. (Например, можно убирать приватные члены, не опасаясь, что сломается что-то вовне редактируемого класса.)

Приватные члены — это хорошо) Они вполне себе нормально реализуются средствами языка через замыкание. Как этот пункт описывает преимущества защищенных методов именно в вашей реализации, не совсем понятно.

> уменьшается количество заявок в bug-трекере, т.к. пользователи библиотеки или контрола могут «зашиться» на наши «приватные» члены, которые в новой версии класса мы решили убрать, либо изменить логику их работы.

Чтобы такого не было, обычно пишут документацию для внешних пользователей, в которой как раз и описывается API библиотеки/контрола/etc, которые можно использовать. Все остальное — нельзя, потому как может поменяться. Ну а имена свойств с нижнего подчеркивания помогут выделить различие еще и визуально.
Еще обычно на каждый баг в трэкере пишут сценарий воспроизведения, из которого часто понятно, что и где использовали и почему оно так могло получиться. Там же сразу и станет ясно, использовали ли недокументированные функции.

> И в целом, защищенные члены класса — это инструмент проектирования. Хорошо иметь его под рукой отлаженным и хорошо протестированным.

Согласен, но если это реализовано и поддерживается на уровне языка, с соответствующими оптимизациями в нативном коде и с минимальными накладными расходами при выполнении. Но в вашем случае это только добавляет сложности в реальном коде и нагрузки при его выполнении.
НЛО прилетело и опубликовало эту надпись здесь

Я уж было думал что высокое искусство накостылить Очередные Единственные Труъ Классы в 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, таким образом
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);
     }
}
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории