под фильтром понимаю код «детё.Возраст <= 12», по уму это ведь должен был быть отдельный класс с реализацией интерфейса IFilter, либо на худой конец язык запросов (подобие nHibernate). А тут функция — и всё.
На функциональном языке код будет выглядеть почти так же, только вместо обращения к методам SelectMany,Where и т. п. Будут, что-то типа Seq.Iter, Seq.Filter, Seq.Distinct
И в ФЯ не будет ниодного объекта или класса :) хотя не знаю последовательности в функциональном программировании считаются объектами или нет? — получается вроде не ООП.
С одной стороны да, с другой по ООП (по крайне мере, которому меня учили): я должен был как минимум создать класс фильтр (чтобы его можно было заменять), реализовать класс группировки и т. п. Здесь нет этого — для многих это не ООП.
Ещё одна маленькая задача которую удалось решить без ООП. Да я используя классы коллекций, да внутри много ООП, которое позволяет мне делать такие вещи. Но почему получается, чем меньше ООП снаружи, тем проще мой код?
Regex reg = new Regex(@«src=»"/media/posters/(?[0-9_a-zA-Z\-]*?)\.thumbnail\.jpg""", RegexOptions.Singleline);
Enumerable.Range(1, int.MaxValue)
.Select(page => new WebClient().DownloadString(string.Format(«demotivators.ru/?page={0}», page)))
.Select(html => reg.Matches(html))
.SelectMany(_ => _.Cast())
.Select(_ => _.Groups[«url»].Value)
.AsParallel().WithDegreeOfParallelism(40)
.Select(name => new
{
name,
url = string.Format(«demotivators.ru//media/posters/{0}.jpg», name),
path = string.Format(@«D:\temp\dem\{0}.jpg», name)
})
.Where(image => !File.Exists(image.path))
.Select(image => new { image.name, image.url, image.path, data = new WebClient().DownloadData(image.url) })
.ForAll(image => File.WriteAllBytes(image.path, image.data));
(извиняюсь, нету кармы, поэтому не могу оформить красиво код).
Но вы только посмотрите, ведь это многопоточная программа по скачиванию картинок с demotivators.ru. Причем нам предварительно нужно скачивать страницу и только потом скачивать картинку. Кто решиться его переписать на ООП с использованием потоков? Сколько получиться кода? Будет ли он таким же прозрачным? Заметьте этот кусок кода умещается на четверть экрана, это можно сказать идеальный код для такой качалки.
(пробовал другие варианты, но обычно очень сложно заставить код скачивать следующую страницу не после того, как на разобранной странице скачены все картинки, а сразу по освобождению выделенного потока)
Да, условие немного расплывчато, хотя довольно четко написано. Есть список родителей, у них поле Дети, у Ребёнка есть такие-то свойства. И как мне кажется, не правильно менять условие задачи, чтобы она подходила под реализацию через SQL или hash set'ы. Редко бывает, что мы можем в готовой системе что-то поменять, а тут требовалась именно доработать.
Мне именно интересен подход ООП, так как после прочтения разных методик написания (SOLID, YAGNI), у меня вышла каша из десятков классов. Хотя задача в том же C#, решается простым LINQ выражением. Каюсь, задачу намеренно усложнил, чтобы было нагляднее видно сложность работы с наборами данных при помощи ООП.
Самое интересное, что это не псевдокод, это вполне рабочий код, который НЕ НУЖНО реиспользовать где-нибудь, т. к. его значительно проще написать там, где нужно ещё раз. Это как раз вариант нарушения всех принципов ООП: для чего нужно писать сложный универсальный код, когда можно написать красивый идеально подходящий именно для этой задачи.
У LINQ есть ещё один плюс, вы почти (!!!) можете не думать о том, где лежат у вас данные, это может быть база, сервис или объекты.
Полностью согласен, уже была статья на хабре о том, как можно сделать из простого сложное с помощью ООП.
Но больше всего мне нравиться то, почему используют ООП, обычно эта фраза произноситься с легким пафосом, прям в лицо стоящему напротив человеку: «ООП позволяет реализовать задачу в разы проще!» и обычно добавляется: «Ты что не видишь, что ли?!». А там лес классов, тысячи взаимосвязей, но зато очень низкая связанность сущностей, как будто мы в день делаем тысячи приложений, в которых надо выдавать подарки и обязательно, прям завтра, используем повторно наш тщательно написанный сегодня код.
А стало ли? Было бы интересно сравнить… Я перешел с Pascal/Delphi на C#, и не очень понял, чем стало удобнее. C# идеальный язык, мне он нравится на много больше, но не ООП, а как раз наоборот: функциональные штучки (LINQ, лямбды, делегаты, анонимные классы), свое библиотекой, где-то синтаксисом и т. п. Но не как не ООП, не понимаю, для чего меня заставляют писать static class, если мне нужна функция?
Почему инкапсуляция состояния всегда приписывается ООП, разве в модулях нельзя было создать скрытые переменные, которые доступны только этому модулю?
Вообще к ООП обычно приписывают горы дополнительных возможностей:
— абстракция — как будто функция не может абстрагировать (или модуль);
— инкапсуляция — попробуйте получить доступ к локальным переменным функции;
— полиморфизм — почему я не могу написать функцию использующую более общую функцию, а реализацию подставить во время выполнения;
Единственное, по моему мнению (где-то читал, но к сожалению источник указать не смогу, вроде у Вирта, про его Оберон): ООП дало нам наследование, но при этом в каждой умной книжке, которая учит нас писать идеальный код, обязательно будет упоминание об ограниченном использовании наследования (обычно сводиться к тому, что не более двух уровней, иногда — только реализация интерфейсов). Так как глубокое наследование это ад для отлова ошибок (особенно если не соблюдать разных принципов, типа Лискоу(в)).
Вот это я никогда не понимал, получается, если выделять таким образом сущности, выделять ответственности конкретные ответственности и т. п. То в итоге мы приходим к тому, что у нас есть множество классов, которые содержат по одному методу (без какого-либо состояния) (например: ВыбиралкаПодарка, ВыдавательПодарочныхСертификатов, РаспределителяПодарков). Но для чего тогда нужен сам класс, почему нельзя просто создать отдельный метод, который назвать ВыбратьПодарок, ВыдатьПодарочныйСертификат, РаспределитьПодарки. Если нужно деление — делите на мелкие функции, внутри этой задачи (метода), зачем их выносить отдельно на тот же уровень абстракции, что и сущности, причем чаще всего такие вспомогательные методы больше никто и никогда не будет использовать (они очень и помечаются как private). Если нужно группировать такие функции, используйте Модули, Namespace'ы и т. п.
Чем такой подход — создание виртуального существительного для реализации глагола, лучше чем создания отдельного глагола? Ведь нам не важно, кто или что раздает подарки, нам важен алгоритм отбора и раздачи подарков, зачем его прятать за виртуальными сущностями?
Сейчас все больше пытаюсь закопаться в объектно-ориентированное программирование, но никак не могу нормально представить, как решается такая простая задача через ООП, как следующая (такие задачи приходиться решать очень часто по ходу работы). Скажите ваше мнение как её элегантно решить через ООП?
Дано: список Работников, у класса Работник есть свойство Дети, у ребёнка есть поле Возраст и Пол.
На новый год начальство решило сделать подарки детям до 14 лет. От нас требуется составить список детей работников (группируем по полу, т. к. подарки должны быть разные). Учитывать, что на фирме может работать оба родителя, но подарок должен быть один.
Очень хотел бы взглянуть на вашу версию реализации данной задачи. Ко мне в голову приходят десятки классов, особенно учитывая принципы SOLID и т. п. Хотя как я узнал — через «функциональщину» это решается парой функций.
на счет зависания — как раз подбирает ошибку методом перебора (в начале с шагом 5, как достигнет нужного размера, то с шагом 1)
да, с прозрачностью не успел, надо сделать так же как у sergey_dobrodey.
http://pastebin.com/u020raes
надо ещё с максимальным размером сообщения поиграться, т. к. похоже не всегда разрешено 30 000 символов.
И в ФЯ не будет ниодного объекта или класса :) хотя не знаю последовательности в функциональном программировании считаются объектами или нет? — получается вроде не ООП.
Regex reg = new Regex(@«src=»"/media/posters/(?[0-9_a-zA-Z\-]*?)\.thumbnail\.jpg""", RegexOptions.Singleline);
Enumerable.Range(1, int.MaxValue)
.Select(page => new WebClient().DownloadString(string.Format(«demotivators.ru/?page={0}», page)))
.Select(html => reg.Matches(html))
.SelectMany(_ => _.Cast())
.Select(_ => _.Groups[«url»].Value)
.AsParallel().WithDegreeOfParallelism(40)
.Select(name => new
{
name,
url = string.Format(«demotivators.ru//media/posters/{0}.jpg», name),
path = string.Format(@«D:\temp\dem\{0}.jpg», name)
})
.Where(image => !File.Exists(image.path))
.Select(image => new { image.name, image.url, image.path, data = new WebClient().DownloadData(image.url) })
.ForAll(image => File.WriteAllBytes(image.path, image.data));
(извиняюсь, нету кармы, поэтому не могу оформить красиво код).
Но вы только посмотрите, ведь это многопоточная программа по скачиванию картинок с demotivators.ru. Причем нам предварительно нужно скачивать страницу и только потом скачивать картинку. Кто решиться его переписать на ООП с использованием потоков? Сколько получиться кода? Будет ли он таким же прозрачным? Заметьте этот кусок кода умещается на четверть экрана, это можно сказать идеальный код для такой качалки.
(пробовал другие варианты, но обычно очень сложно заставить код скачивать следующую страницу не после того, как на разобранной странице скачены все картинки, а сразу по освобождению выделенного потока)
Мне именно интересен подход ООП, так как после прочтения разных методик написания (SOLID, YAGNI), у меня вышла каша из десятков классов. Хотя задача в том же C#, решается простым LINQ выражением. Каюсь, задачу намеренно усложнил, чтобы было нагляднее видно сложность работы с наборами данных при помощи ООП.
ГотовыеСписки = Работники
.SelectMany(работник=>работник.дети)
.Where(детё=>детё.Возраст <= 12)
.Distinct()
.GroupBy(детё=>детё.Пол)
Console.WriteLine(string.Join("\r\n", ГотовыеСписки[Мальчик].Select(детё=>детё.Имя));
Console.WriteLine(string.Join("\r\n", ГотовыеСписки[Девочка].Select(детё=>детё.Имя));
Самое интересное, что это не псевдокод, это вполне рабочий код, который НЕ НУЖНО реиспользовать где-нибудь, т. к. его значительно проще написать там, где нужно ещё раз. Это как раз вариант нарушения всех принципов ООП: для чего нужно писать сложный универсальный код, когда можно написать красивый идеально подходящий именно для этой задачи.
У LINQ есть ещё один плюс, вы почти (!!!) можете не думать о том, где лежат у вас данные, это может быть база, сервис или объекты.
Но больше всего мне нравиться то, почему используют ООП, обычно эта фраза произноситься с легким пафосом, прям в лицо стоящему напротив человеку: «ООП позволяет реализовать задачу в разы проще!» и обычно добавляется: «Ты что не видишь, что ли?!». А там лес классов, тысячи взаимосвязей, но зато очень низкая связанность сущностей, как будто мы в день делаем тысячи приложений, в которых надо выдавать подарки и обязательно, прям завтра, используем повторно наш тщательно написанный сегодня код.
Вообще к ООП обычно приписывают горы дополнительных возможностей:
— абстракция — как будто функция не может абстрагировать (или модуль);
— инкапсуляция — попробуйте получить доступ к локальным переменным функции;
— полиморфизм — почему я не могу написать функцию использующую более общую функцию, а реализацию подставить во время выполнения;
Единственное, по моему мнению (где-то читал, но к сожалению источник указать не смогу, вроде у Вирта, про его Оберон): ООП дало нам наследование, но при этом в каждой умной книжке, которая учит нас писать идеальный код, обязательно будет упоминание об ограниченном использовании наследования (обычно сводиться к тому, что не более двух уровней, иногда — только реализация интерфейсов). Так как глубокое наследование это ад для отлова ошибок (особенно если не соблюдать разных принципов, типа Лискоу(в)).
Чем такой подход — создание виртуального существительного для реализации глагола, лучше чем создания отдельного глагола? Ведь нам не важно, кто или что раздает подарки, нам важен алгоритм отбора и раздачи подарков, зачем его прятать за виртуальными сущностями?
Дано: список Работников, у класса Работник есть свойство Дети, у ребёнка есть поле Возраст и Пол.
На новый год начальство решило сделать подарки детям до 14 лет. От нас требуется составить список детей работников (группируем по полу, т. к. подарки должны быть разные). Учитывать, что на фирме может работать оба родителя, но подарок должен быть один.
Очень хотел бы взглянуть на вашу версию реализации данной задачи. Ко мне в голову приходят десятки классов, особенно учитывая принципы SOLID и т. п. Хотя как я узнал — через «функциональщину» это решается парой функций.