Каков ваш лучший пример нарушения принципа единой ответственности? - PullRequest
3 голосов
/ 30 августа 2009

Я ищу несколько хороших примеров кода, который нарушает принцип единой ответственности. Не показывайте мне примеры из книг или веб-сайтов дяди Боба, так как они размазаны по всему Интернету, как этот:

interface Modem
{
    public void dial(String pno);
    public void hangup();
    public void send(char c);
    public char recv();
}

Ответы [ 6 ]

11 голосов
/ 31 августа 2009

Степень детализации вашего ОО-проекта - дело вкуса и может не подходить для других. Таким образом, я бы не стал искать примеры нарушения принципа единой ответственности в каком-то классе бизнес-логики, а обсуждать, слишком много или мало нужно сделать.

На мой взгляд, лучшие примеры (с наихудшими побочными эффектами) приходят от нарушения уровня вашего приложения. F.ex.:

  • Выполнение бизнес-логики на уровне доступа к данным (единственной обязанностью которого является обеспечение постоянного доступа к приложению)
  • Доступ к бизнес-сервисам из (через) модели домена (единственной обязанностью которой является хранение большей части состояния приложения)
  • Выполнение сложной бизнес-логики на уровне представления (отвечает за представление данных и ввод данных пользователем)
4 голосов
/ 31 августа 2009

Вот некоторый код из проекта PHP, который мне пришлось взять:

class Session
{
    function startSession()
    {
        // send HTTP session cookies
    }

    function activateUserAccount()
    {
        // query the DB and toggle some flag in a column
    }

    function generateRandomId()
    {}

    function editAccount()
    {
        // issue some SQL UPDATE query to update an user account
    }

    function login()
    {
        // perform authentication logic
    }

    function checkAccessRights()
    {
        // read cookies, perform authorization
    }
}

Я полагаю, что этот класс очень важен.

1 голос
/ 31 августа 2009

На самом деле, в большинстве языков OO, которые я использовал, класс Object верхнего уровня является хорошим примером. Например, в Ruby класс Object (или, точнее, Kernel mixin, который смешивается с Object) имеет 45 открытых методов экземпляра. Некоторые из них являются псевдонимами, но их должно быть не менее 20, и они повсюду. Я легко могу определить как минимум 5 обязанностей.

Теперь я не хочу выбирать Руби. Это мой любимый язык программирования. Вот почему я использовал его в качестве примера: потому что это язык, с которым я больше всего знаком. И я вполне уверен, что то, что я написал о Ruby, применимо на 100% по крайней мере к Java и .NET.

0 голосов
/ 29 июня 2015
#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>

@interface Spreadsheet : NSObject

- (void)loadFromURL:(NSURL *)url;
- (void)saveToURL:(NSURL *)url;
- (void)drawTo:(CGRect*)targetArea withContext:(CGContextRef *)context;

@end

Я бы сказал, что приведенный выше пример нарушает SRP.

На первый взгляд ясно, что класс отвечает за одну вещь: электронные таблицы. Он отличается от других объектов в проблемной области управления документами, таких как обработка текстов.

Однако рассмотрите причины, по которым объект электронной таблицы может измениться.

Возможно изменение модели, лежащей в основе электронной таблицы. Это влияет на загрузку и сохранение кода, но не влияет на отображение таблицы. Поэтому обязанности по загрузке / сохранению отделены от обязанностей по рисованию. Наш класс имеет две обязанности.

Так что, если мы подумаем обо всех разумно предсказуемых причинах изменения класса и увидим, что это повлияет только на конкретные методы класса, мы увидим возможность выделить ответственность за получение более сфокусированного класса.

Пересмотренный класс будет:

@interface SpreadsheetEncoder

- (NSData *)encodedSpreadsheet:(Spreadsheet *)spreadsheet;
- (Spreadsheet *)spreadsheetFromEncodedData:(NSData *)data;

@end

@interface Spreadsheet2 : NSObject

- (NSData *)data;
- (instancetype)initSpreadsheetFromData:(NSData *)data;
- (void)drawTo:(CGRect*)targetArea withContext:(CGContextRef *)context;

@end

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

СРП, на мой взгляд, сводится к вопросу "что может измениться?" и «что будет затронуто». Когда «что может изменить» отображает только одну вещь, на которую влияют, у вас есть классы, реализующие принцип SRP.

0 голосов
/ 18 декабря 2013

Это качественный вопрос, чтобы выяснить «обязанности» класса.
Просто глядя на код данного класса, ни в коей мере не может дать нам представление о том, насколько хорошо он обрабатывает свою ответственность.
По моему опыту очень необходимо принять во внимание, как изменения требований к классу будут распространяться на другие модули (или как изменения от других классов будут распространяться на этот класс).

Поскольку @schmeedy дает хорошее объяснение «нарушения многоуровневой системы», которое, я думаю, является лишь одним из способов анализа «области ответственности».

Я попытался немного углубить обсуждение. Я пытаюсь определить «ответственность» количественно.
Некоторые обсуждения в моем блоге: http://design -principle-pattern.blogspot.in / 2013/12 / single-liability-принцип.html

0 голосов
/ 30 августа 2009

Ключ к SRP состоит в том, чтобы определить обязанности, чтобы ваша реализация выполняла именно это. Это похоже на то, что вы делаете правило (присваивая классу имя и ответственность), а затем пытаетесь следовать ему.

Так что, если вы не следуете этому правилу, вы либо не определяете правило должным образом, либо вы непоследовательны при его реализации (или обоих, что на самом деле может быть наиболее распространенным случаем). 1007 *

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

...