Pull to refresh

Comments 15

К SRP принцип единой ответственности не имеет отношение. Под SRP понимается принцип единого ответственного. Это хотя часто взаимозависимые понятия, но они в корне разные.

Простите, что за "принцип единого ответственного"? Принцип единственной ответственности (SRP) я знаю https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B8%D0%BD%D1%86%D0%B8%D0%BF_%D0%B5%D0%B4%D0%B8%D0%BD%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE%D1%81%D1%82%D0%B8, а что за другой принцип "единого ответственного"?

Ну, почитайте источники, блин, а не наколенное использование:

Из всех принципов SOLID наиболее трудно понимаемым является принцип единственной ответственности (Single Responsibility Principle, SRP). Это, вероятно, обусловлено выбором названия, недостаточно точно соответствующего сути. Услышав это название, многие программисты решают: оно означает, что каждый модуль должен отвечать за что-то одно.

Самое интересное, что такой принцип действительно существует. Он гласит: функция должна делать что-то одно и только одно. Этот принцип мы используем, когда делим большие функции на меньшие, то есть на более низком уровне. Но он не является одним из принципов SOLID — это не принцип единственной ответственности. Традиционно принцип единственной ответственности описывался так:

Модуль должен иметь одну и только одну причину для изменения.

Программное обеспечение изменяется для удовлетворения нужд пользователей и заинтересованных лиц. Пользователи и заинтересованные лица как раз и есть та самая «причина для изменения», о которой говорит принцип. Фактически принцип можно перефразировать так:

Модуль должен отвечать за одного и только за одного пользователя или заинтересованное лицо.

К сожалению, слова «пользователь» и «заинтересованное лицо» не совсем правильно использовать здесь, потому что одного и того же изменения системы могут желать несколько пользователей или заинтересованных лиц. Более правильным выглядит понятие группы, состоящей из одного или нескольких лиц, желающих данного изменения. Мы будем называть такие группы акторами (actor). Соответственно, окончательная версия принципа единственной ответственности выглядит так:

Модуль должен отвечать за одного и только за одного актора.

В той же английской вики написано всё верно

Вы смешали вместе принципы хорошего кода для процедурного программирования и для ООП. Да, Одна функция должна отвечать за что-то одно. Но это принцип процедурного программирования. Он остался еще в шестидесятые, не надо его тянуть в SOLID. Это раз.

Да, проблема внедрения SOLID и SRP обусловлена еще и тем, что пользователи, ознакомившись с принципом "Класс (модуль) должен отвечать за что-то одно", решают, что этот класс имплементирует только один метод (я с этим сталкиваюсь). Буквально, один класс- один метод Invoke. Нет, Дядя Боб (чуть не описался Дядя Бог), объяснял, что класс может иметь хоть сто публичных методов, но он должен делать что-то одно. Да, он говорил, что класс должен делать что-то только для одного актора, грубо говоря, класс может делать выписку счета, сторнирование счета, корректировку счета - только для бухгалтера, но не имеет право делать что-то для расчетчика, считать расход электроэнергии, к примеру.

Но это тоже не то. Печать счета - это для бухгалтера, по-вашему? То есть, нужно имплементировать функционал печати счета в класс Bill, ведь в нем заинтересован один и тот-же бухгалтер?

Нет, согласно идеологии чистого кода, печать (для вывода на принтер, для вывода на экран, для вывода в PDF файл) должны осуществлять другие классы (каждый свой) по определенному интерфейсу. В классе счета (как и в классе процессора счетов), кстати, даже dependency ни на интерфейс, ни на тем более классы печати быть не должно, согласно принципу инверсии зависимостей.

И тем более, какие пользователи, группы или лица должны быть отражены в классах, скажем работы с файловой системой, скажем в Java? При том, что набор классов работы с потоками и файлами очень грамотно реализован, в соответствии с SOLID.

Вся система Spring реализована на SOLID, буквально можно изучать как учебник. Какие там акторы?

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

Во вторых, мы не говорим класс в контексте SRP. Мы говорим о модуле. В модуле может быть несколько классов. А может быть и один. И если вам для реализации печати нужен какой то свой класс - то делайте его, но не называйте это следованию принципа SRP. Можете назвать это принципом разделения функционала, или принципом единообразия реализации, но не SRP. И да, если классу надо уметь себя распечатывать, то надо просто добавить в него метод print, а не создавать класс [ObjectType]Printer. За исключением, если ваш бухгалтерский отчет должен распечатывать, например, специалист по закупкам, в своем, закупочном, формате. Тогда, да, согласно SRP мы выделяем отдельный метод для формирования нового класса BookingReportPurchasing, из нового модуля, и отдельный метод print в этом классе (ну по вашему отдельный класс BookingReportPurchasingPrinter), а ответственность за аналитику модуля "возлагаем" на специалиста по закупкам.

Так что не надо чистый код путать с чистой архитектурой. Это 2 раздельных уровня. Архитектору, часто, не важно как ваш internal код реализован, это важно техлиду вашей группы, максимум. А вам, как чистокодмену не важна архитектура, пока к вам не спустится архитктор и не спросит: а какого нахрен черта.

В этом и есть смысл SOLID. Если у вас актор из Spring.Boot начнет влиять на реализацию в Spring.Security - это нарушение SRP. Но, если у вас у какого то класса оказалось 100500 методов внутри Spring.Boot, вопросы конечно возникнут в сфере разделения функционала, но вопросы в сфере разделения ответственности - не будет.

Вы оперируете в контексте единой ответственности функциями, хотя главное это данные, с которыми работают функции. Вся соль в связности классов.

Да это бесконечный холивар, тут бесполезно убеждать. Сам принцип слишком абстрактый. Поэтому его каждый понимает по-своему. Либо из-за того, что он изначально сформулирован не совсем удачно.

Это не может быть правдой, потому что в английском не употребляются прилагательные без существительного. Для мифического "принципа единого ответственного" аббревиатурой было бы, например, SROP (single responsible object principle).

Хоть принцип действительно называется single-responsibility principle (через дефис), но отвечает он не за функционал, а за актора: A module should be responsible to one, and only one, actor

- Если покупки на сумму более 10 000 единиц, покупателю предоставляется скидка в 3%.

- Доставка товара на сумму более 15 000 единиц осуществляется бесплатно. В ином случае цена доставки составляет 5% от суммы.

Код для этого сделан плохо. Причем Discount дублирует Delivery, см метод calculate.

Я бы сделал по другому.
Класс который применяет фильтры Discount и Delivery, то есть метод calculate внутри себя вызывает указатели на vector указателей на Discount и Delivery.

И тогда если добавится новая скидка, мне ненужно реализовывать метод calculate, я просто напишу еще один фильтр и добавлю его как push_back к двум предыдущим. В этом же смысл SPR, не?

Попробуйте переписать код и он станет и меньше и проще.

Пример кода, накидан в блокноте. Суть ясна.

class SaleInfo
{
public:
	int Condition;
	int Percent;
};

class SaleService
{
public:
	bool Calc(const std::vector<SaleInfo>& list)
	{
		// sort list от большего к меньшему

		for (auto& i : list) // access by reference to avoid copying
		{
			if (i.Condition >= Cost)
			{
				Cost += i.Percent;

				//Скидка применилась
				return true;
			}
		}

		//Скидка не прошла
		return false;
	}
};

class textEditor

Тема не раскрыта. К примеру пусть у нас есть структура документа textData

Для оперирования над данной структурой. Создаем классы textFinder, textReplacer ит.д

И в аргументы методов передаем textData. textData не знает о других классах, а вот как раз внешние классы о ней знают и могут ее модифицировать.

Итог: когда показывают примеры на слонах и пингвинах, выглядит хорошо. При усложнении кода связей, требуется дополнительная аналитика.

"Принцип единственной ответственности обозначает, что каждый объект должен иметь одну обязанность и эта обязанность должна быть полностью инкапсулирована в класс" - неужели этой информации недостаточно, что потребовалось написать статью? Что там дальше следует? Ждём статью по принципу открытости- закрытости?

Sign up to leave a comment.

Articles