Кстати, да. Спасибо за код.
Этот способ более красивый, чем мой финальный. Отсутствие общего предка у std::less и std::greater ставило передо мной непреодолимый забор.
Вы ожидали увидеть в статье весь проект? Надо было напустить пыли в глаза, чтобы читатель устал читать пояснения, какой класс для чего нужен, в какой уровень вливает данные и почему он это делает именно так?
Суть происходящего описана в статье вполне прозрачно:
— производится единообразное наполнение (какая разница — одной функцией Fill, или целой цепочкой классов);
— производится почти единообразное использование (в постановке задачи я указал, что использоваться будет много где, т.е. небольшое неудобство умножится, плюс возрастёт риск ошибок);
— map не лежит просто голый посреди кода, как int a из прошлого моего коммента, и не запрятан в private класса за кучей оберток, а является именно public-полем структуры. Т.е. есть возможность рядом в этой структуре разместить еще какие-то поля, и даже немного кода (много не хочется, потому что да, оно тогда станет больше похоже на класс).
«Тысячи человеко-часов» потрачены на абстрактную реализацию, которая как правило не применяется полностью
Весь STL и map в том числе — это хорошо спроектированная библиотека. Приведенный в статье Storage — это в общем-то тоже библиотека, но только «для собственного применения». Если я обеспечу интерфейс только к части функциональности map — я ограничу возможное использование. Лучший способ сделать мне настолько же хорошо — это просто повторить. В данном случае — повторить не реализацию, а интерфейс map. Всё, что я спроектирую сам за разумное время — будет в лучшем случае на две головы ниже, и мне не понятно, почему Вы этого не понимаете, говоря о проектировании.
Если потребителя данных не пугает сложность map — то что мне мешает «выпятить» его наружу? Это ни в коем случае не внутренний механизм, позволяющий классу делать какую-то магию и выдавать наружу только её результат. Это — хранилище, которое в одном модуле наполняется, а в другом используется.
Если есть однотипная обработка, то логично её тоже положить рядом с данными, не так ли?
Вовсе не факт. Данные ведь тоже не из воздуха берутся и не рандомно генерируются… Т.е. реально это всё вопросы удобства каждого из вариантов в контексте конкретного применения. И не более. И вопрос в прошлом комменте я намеренно поставил некорректно, чтобы это стало понятно.
P.S. Да, про struct, возможно, немного старомодно, но я до сих пор не пойму зачем вообще дали возможность в плюсах добавлять код туда.
Полностью согласен.
struct не class
В мире кроме черного и белого есть еще много-много промежуточных вариантов. В данном случае в реальном проекте это структура с небольшим количеством кода и небольшим количеством private. До класса по сути ей очень далеко.
Объясните для чего вам повторять интерфейс, если вы используете 2 метода?
Еще спросите, зачем мне вообще городить весь этот огород, если на самом деле мне надо всего лишь вывесть в cout несколько повторяющихся чисел.
Это всего лишь пример. И при использовании данных, хранящихся в этой структуре, мне надо будет не только пройти ее «от и до», но понадобится еще десяток способов использования. На проектирование интерфейса map потрачены тысячи человеко-часов, и я вполне отдаю себе отчет, что ничего подобного я не могу себе позволить (и в данном проекте, и вероятно вообще).
Кроме того, спрятать map — значит, обрезать возможность использования member-functions, часть из которых эффективнее своих общих аналогов. А это значит — или заложить в архитектуру снижение производительности, или сделать для этих методов обертки. Оба решения — так себе.
Ну и напоследок — 3 примера кода:
1.
int a = 0;
2.
struct Storage
{
int a = 0;
};
3.
class Storage
{
public:
Storage() : a(0) {};
~Storage(){};
int getA() const {return a;};
void setA(const int new) {a = new;};
private:
int a;
};
я бы не стал давать во вне map, сделал бы все внутри класса с методами заполнения и доступа
Это примерно мой вариант про инкапсуляцию. В проекте признан нецелесообразным, т.к. чтобы реализовать его полноценно — надо проделать работы раз в 20 больше. Ради чего? Ради того, чтобы примерно повторить интерфейс усредненного STL-контейнера.
В случае «сферического кода в вакууме» я тоже соглашусь, что лучше все попрятать и сделать интерфейс, не зависящий от типа контейнера и прочих моментов. Но, заметьте, в статье именно struct. Т.е. это хранище, в котором почти нет private, почти нет кода, а доступ ограничивается на более высоких уровнях (да, оно завернуто еще в 2 уровня хранилищ, потому что именно так построена предметная область).
Интересно, если бы Страуструп опубликовал главу готовящейся книги в статье на Хабре — его бы тоже заплевали? Мне кажется, что да, потому что половина комментаторов сказала бы, что он пишет банальные очевидные вещи, которые и так описаны в стандарте, а другая половина сказала бы, что это слишком заумно и в реальной жизни неприменимо.
Во-первых, статья не только об одном финальном способе.
Во-вторых, правильная формулировка — это уже половина решения. А когда есть только постановка задачи — до формулировки вопроса еще далеко.
Ну и в-третьих, понять, что один из десятков почти не прокомментированных примеров кода является именно нужным решением, кажется простым только «задним числом».
Этот способ более красивый, чем мой финальный. Отсутствие общего предка у std::less и std::greater ставило передо мной непреодолимый забор.
Только сухая документация — это одно, а понимание, для чего оно может быть применено — это немножко другое.
И если применить знания о способах усвоения человеком информации, то при чтении хелпов не задействуются почти никакие типы памяти.
Вы ожидали увидеть в статье весь проект? Надо было напустить пыли в глаза, чтобы читатель устал читать пояснения, какой класс для чего нужен, в какой уровень вливает данные и почему он это делает именно так?
Суть происходящего описана в статье вполне прозрачно:
— производится единообразное наполнение (какая разница — одной функцией Fill, или целой цепочкой классов);
— производится почти единообразное использование (в постановке задачи я указал, что использоваться будет много где, т.е. небольшое неудобство умножится, плюс возрастёт риск ошибок);
— map не лежит просто голый посреди кода, как int a из прошлого моего коммента, и не запрятан в private класса за кучей оберток, а является именно public-полем структуры. Т.е. есть возможность рядом в этой структуре разместить еще какие-то поля, и даже немного кода (много не хочется, потому что да, оно тогда станет больше похоже на класс).
Весь STL и map в том числе — это хорошо спроектированная библиотека. Приведенный в статье Storage — это в общем-то тоже библиотека, но только «для собственного применения». Если я обеспечу интерфейс только к части функциональности map — я ограничу возможное использование. Лучший способ сделать мне настолько же хорошо — это просто повторить. В данном случае — повторить не реализацию, а интерфейс map. Всё, что я спроектирую сам за разумное время — будет в лучшем случае на две головы ниже, и мне не понятно, почему Вы этого не понимаете, говоря о проектировании.
Если потребителя данных не пугает сложность map — то что мне мешает «выпятить» его наружу? Это ни в коем случае не внутренний механизм, позволяющий классу делать какую-то магию и выдавать наружу только её результат. Это — хранилище, которое в одном модуле наполняется, а в другом используется.
Вовсе не факт. Данные ведь тоже не из воздуха берутся и не рандомно генерируются… Т.е. реально это всё вопросы удобства каждого из вариантов в контексте конкретного применения. И не более. И вопрос в прошлом комменте я намеренно поставил некорректно, чтобы это стало понятно.
Полностью согласен.
В мире кроме черного и белого есть еще много-много промежуточных вариантов. В данном случае в реальном проекте это структура с небольшим количеством кода и небольшим количеством private. До класса по сути ей очень далеко.
Еще спросите, зачем мне вообще городить весь этот огород, если на самом деле мне надо всего лишь вывесть в cout несколько повторяющихся чисел.
Это всего лишь пример. И при использовании данных, хранящихся в этой структуре, мне надо будет не только пройти ее «от и до», но понадобится еще десяток способов использования. На проектирование интерфейса map потрачены тысячи человеко-часов, и я вполне отдаю себе отчет, что ничего подобного я не могу себе позволить (и в данном проекте, и вероятно вообще).
Кроме того, спрятать map — значит, обрезать возможность использования member-functions, часть из которых эффективнее своих общих аналогов. А это значит — или заложить в архитектуру снижение производительности, или сделать для этих методов обертки. Оба решения — так себе.
Ну и напоследок — 3 примера кода:
1.
2.
3.
Какой из вариантов лучше?
Это примерно мой вариант про инкапсуляцию. В проекте признан нецелесообразным, т.к. чтобы реализовать его полноценно — надо проделать работы раз в 20 больше. Ради чего? Ради того, чтобы примерно повторить интерфейс усредненного STL-контейнера.
В случае «сферического кода в вакууме» я тоже соглашусь, что лучше все попрятать и сделать интерфейс, не зависящий от типа контейнера и прочих моментов. Но, заметьте, в статье именно struct. Т.е. это хранище, в котором почти нет private, почти нет кода, а доступ ограничивается на более высоких уровнях (да, оно завернуто еще в 2 уровня хранилищ, потому что именно так построена предметная область).
Если убрать const перед ml и mg — работает.
Во-вторых, правильная формулировка — это уже половина решения. А когда есть только постановка задачи — до формулировки вопроса еще далеко.
Ну и в-третьих, понять, что один из десятков почти не прокомментированных примеров кода является именно нужным решением, кажется простым только «задним числом».