Комментарии 16
НЛО прилетело и опубликовало эту надпись здесь
Не вижу смысла такое делать, кроме как для перегрузки операторов (оператор действительно иногда удобнее делать внешним). Что так объявлять френдом функцию, что писать ее методом в private область и точно также определять во внешнем файле (если уж очень не хочется показывать «пользователю»).
НЛО прилетело и опубликовало эту надпись здесь
Имхо, пример неудачный, потому что и size, и empty в данном случае должны быть именно методами — прятать их нет смысла. А то, что можно спрятать, чаще всего имеет дело с приватными членами. Вобщем, совет неплохой, но в большинстве случаев бесполезный.
Там в самой статье есть примеры с eat и sleep. Если функции используют только public интерфейс, то их можно выносить.
Но нужно ли? Как раз в том примере из статьи у меня есть сомнения, что это надо делать.
если при реализации новой имплементации получится, что реализовывать sleep через eat — очень медлено, то метод мы сможем переопределить, а внешнюю функцию — нет.
а вообще, если не хочется расширять интерфейс базового класса — есть замечательный паттерн «декоратор».
В этой статье декоратор примерно и описан, только глобальный, без отдельного класса-декоратора :)
угу, гигантский такой декоратор ко всем объектам в системе под названием «main» =)
Может не во всём хорошо разобрался, заранее приношу извинения, но вот пара вопросов, возникших у меня:

Почему вообще возникает желание выносить приватные методы куда-либо из класса? Ведь на приватные, как на неизменные, ложится реализация базиса класса, его костяк, которые никаким наследованием не должен принципиально изменяться. Именно в продумывании приватного поведения (внутреннего программного интерфейса) заключается продумывание поведение класса. Чаще всего именно так, имхо.

Почему, опять же, поднимается вопрос прятанья каких-либо методов от интерфейса класса, если эти методы являются приватными? Это ведь абсолютно внутренний интерфейс, а не внешний. Зачем его куда-то ещё прятать, если он уже приватный и недоступный никому из-вне?
1. приватный интерфейс задумывался, как внутренний, но фактически в С++ он внешний, т.к. находится там же, где и внешний интерфейс — в определении класса. А значит клиент должен делать ребилд каждый раз при изменении даже скрытого интерфейса. Даже при простом рефакторинге или добавлении\удалении функций, закрытых или открытых, неважно.
2. Если функции выносить из класса, то ребилд надо будет делать только тем клиентам, которые реально используют именно измененную функцию.
3. Мы можем спрятать внутреннюю реализацию класса и упростить и улучшить его вид такими вынесениями функций.
1) То есть вопрос дистрибьюции программного пакета вынуждает нас менять архитектуру этого пакета?.. Как-то странно. Понимаю, что решение подобных вопросов позволяет уменьшить время, затрачиваемое на внедрение обновлённого компонента или автоматизацию какой-то части рутинной работы. Но здесь идея преподносится так, как будто это реально оправданная задача с точки зрения ООПроектирования.

2) Как клиенты могут использовать приватную функцию?.. Зачем им вообще знать, что приватный метод класса изменился? Ведь клиент использует класс полностью через внешний интерфейс, как чёрный ящик. Я прав? Просто отдаём из новый скомпилированную библиотеку, если это абсолютно чёрный ящик. Или отдаём новые сорцы класса на компиляцию, гарантируя то, что внушний интерфейс класса остался прежним, а изменился лишь приватный метод.

3) Зачем что-то прятать от людей? Если метод реализован как private, то уже никакому нормальному человеку не должно приходить в голову пытаться переопределять его. Разве не так? Если ему нужно изменять приватные методы, то значит класс плохо спроектирован, либо в него не были заложены понадобившиеся возможности. Это вопрос рефакторинга. Просто опять не могу увидеть плюса в этих прятаньях метода от кого-то.

Я так понял, у вас файлы с вынесенными в статичными функциями компилируются как некая отдельная библиотека, раз уж вы упоминаете вопросы перекомпиляции. Но, по моему, выигрыша во времени или чем-либо другом, при возникновении необходимости перекомпиляции из-за внесенных изменений в private методах классах, совершенно не возникает.

P.S. Я в проблематике компилируемых языков плохо разбираюсь, совсем неофит. Поэтому, может, мои рассуждения со стороны выглядят нелепо или вообще походят на софизм. Вы скажите, промолчу и пойду читать Страуструпа ))
1. Я не имею в виду дистрибуцию. Клиент класса — это любой код, использующий его. В том числе и ваш локальный.
2. Тут вопрос теоретический. Что такое инкапсуляция? Для класса Мейерс пишет: «We've now seen that a reasonable way to gauge the amount of encapsulation in a class is to count the number of functions that might be broken if the class's implementation changes.» А значит логично уменьшать это число функций :)
3. Прятать надо всегда, если не хочешь, чтобы кто-то что-то не так не использовал :) Всё, что не спрятано, будет найдено и использовано. Конечно, это касается в основном библиотек.
Я не могу понять смысл фразы Мейерса в словах «functions that might be broken»… Кем broken? Какого фига он их broken? =)
Ведь из термина инкапсуляции в ключе взаимодействия классов само-собой вытекает необходимость сохранения 100% внешнего интерфейса класса, если мы хотим обеспечить дальнейшую работоспособность его клиентов.
Если это принять как постулат в текущей ситуации, то значит мы должны озаботиться тем, чтобы у класса всегда оставались N публичных методов, через которые с ним работают клиенты. И никакая имплементация этого класса не должна менять ожидаемого результата работы этих методов. Т.е. нужно соблюдать обычные рамки входных и выходных аргументов. Если мы придерживаемся этих условий, то и недостаточной инкапсуляции, по моему, не возникает в принципе.

Ну не может же метод calcSin(double grad) после изменений в нём начать форматировать винчестер, какие бы изменения в ней не были произведены? Это же фантастика. Если реализована хорошая атомарность классов и их (хотя бы публичных) методов, то ситуаций изменения смысла и типа возвращаемого клиенту значения просто не возникает.

С всем утвержеднием «gauge the amount of encapsulation in a class is to count the number of functions that might be broken if the class's implementation changes» я не согласен…

Инкапсуляция это ведь не гарантия того, что класс будет работать после ковыряния в нём программиста (broken'а функций, эволюции класса), а принцип того, что у нас есть возможность выделить общедоступный способ взаимодействия с классом и спрятать сокровенные потроха от жадных рук. Ничего большего она нам сама по себе не позволяет делать. Если мы изменили правила общедоступного обращения, то тут уж как не крути, а всем остальным нужно перестраиваться.

В общем, я до сих пор проблематики с точки зрения проектирования уловить не смог :\
блин, скушалось все…

Private implementation — это вырожденный вариант вариант паттерна мост en.wikipedia.org/wiki/Design_Patterns (довели, что уже не могу ссылки вставлять). А по статье, скажу, ИМХО, главное не объектность синтаксиса, а объектность в проектировании, и какими уже средствами это добивается — дело конкретной ситуации. Всё имеет право на жизнь.
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.