Рубрики
Без рубрики

Принцип единой ответственности (SRP)

Принцип единой ответственности (SRP) является одним из аспектов Принципов SOLID. В нем говорится, что… С пометкой “качество кода”, “java”, “ооп”.

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

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

Давайте рассмотрим очень простой для идентификации пример. Может быть довольно сложно идентифицировать организацию, которая идет против SRP. Мы начнем с простого квадратного класса, который содержит одно поле – длину стороны квадрата. В этом классе есть два метода: getter и setter для нашего одного поля. Ясно, что этот класс несет одну ответственность и поэтому следует SRP. Он отвечает за удержание одного поля “sideLength”.

public class Square {

  private int sideLength;

  public int getSideLength(){
    return sideLength;
  }

  public void setSideLength(int sideLength){
    this.sideLength = sideLength;
  }

}

Теперь мы добавляем метод под названием ‘getArea’, который возвращает площадь квадрата. Мы добавили дополнительную функциональность в наш класс, так что теперь он может делать две вещи. Вы можете подумать, что теперь это противоречит SRP, поскольку у него есть две вещи, за которые он отвечает: длина стороны и вычисление площади. Однако, если мы изменим абстракцию нашего контекста SRP, мы увидим, что мы все еще следуем правилу. Вместо того, чтобы класс отвечал за заботу об одном поле, теперь он заботится о нашей “квадратной” форме, а также о полях и операциях, которые нам нужны для этого объекта. Он отвечает за обработку квадратных форм. Важно отметить, что каждый метод в нашем классе отвечает за одну вещь, наш метод “getArea” не делает ничего другого, кроме возврата вычисленной области.

public class Square {

  private int sideLength;

  public int getSideLength(){
    return sideLength;
  }

  public void setSideLength(int sideLength){
    this.sideLength = sideLength;
  }

  public int getArea(){
    return sideLength * sideLength
  }

}

Теперь пришло время нарушить принцип единой ответственности. Мы добавили в наш класс square метод под названием ‘isUserAuthenticated’, который проверяет, прошел ли пользователь аутентификацию в нашей системе. Понятно, что этот метод неуместен, он не принадлежит к этому классу, поскольку не имеет ничего общего с нашим квадратным объектом. Этот новый метод нарушил SRP в контексте нашего класса.

public class Square {

  private int sideLength;

  public int getSideLength(){
    return sideLength;
  }

  public void setSideLength(int sideLength){
    this.sideLength = sideLength;
  }

  public boolean isUserAuthenticated(User user){
    // Do something here
    return false;
  }

}

Предыдущий пример был довольно очевиден, когда мы нарушили принцип единой ответственности. Теперь давайте рассмотрим более реальный сценарий, с которым вы могли бы иметь дело в реальной кодовой базе или на работе. Приведенный ниже класс User показывает набор полей, которые соответствуют пользователю; его имя пользователя, пароль, имя и фамилия, дата рождения, адрес и т.д. Технически это соответствует SRP, поскольку он имеет дело только с вещами, связанными с пользователем, в этом классе нет ничего странного или вырванного из контекста. Однако, если мы посмотрим внимательнее и подумаем о том, какой другой код может быть внутри этого класса, мы могли бы рассуждать по-другому.

public class User {

  private String username;
  private String password;
  private String firstName;
  private String lastName;
  private Date dob;
  private String addressFirstLine;
  private String addressSecondLine;
  private String Country;
  private String addressPostcode;
  private String contactNumber;
  private String emailAddress;

  // Getters & Setters
  // + validation

}

Мы могли бы утверждать, что адресные части класса связаны с чем-то другим, у них другой контекст. Мы могли бы перенести их в новый класс под названием Address. Мы могли бы утверждать то же самое с полями контактного номера и адреса электронной почты, поскольку они связаны с контактными данными. Это простые способы, которыми мы можем уменьшить область действия нашего класса, сохраняя при этом верность SRP.

С каждым из этих полей у нас может быть проверка, чтобы обеспечить надежный пароль или действительный адрес электронной почты. Проверка этих полей может быть перенесена в отдельное место, поскольку проверка – это другая ответственность за хранение информации. У нас также может быть код базы данных внутри этого класса для сохранения и извлечения пользователей из нашей базы данных. Этот код также может быть перемещен за пределы класса. Как вы можете видеть, SRP может быть очень сложным при работе с реальными примерами, но важно подумать о том, какова цель вашего класса, и извлечь любой другой код. Является ли это целью хранения информации о пользователе, проверки определенного поля, обработки взаимодействий с базой данных, ведения журнала?

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

К счастью, если мы используем Spring, который является фреймворком для языка программирования Java, существует модуль, называемый Аспектно-ориентированным программированием (AOP). Я не буду вдаваться в подробности о том, как использовать AOP или как работает приведенный ниже код, так как я оставлю это для другого раза. AOP позволяет нам устранять эти сквозные проблемы, такие как ведение журнала или аутентификация. Сквозная проблема – это, по сути, какой-то фрагмент кода или функциональности, который появляется во множестве модулей или мест в коде. Используя AOP, мы можем устранить эти проблемы и по-прежнему следовать SRP.

@Aspect
public class UserAspect {

  private static final Logger LOGGER=LoggerFactory.getLogger(UserAspect.class);

  @Before("execution(public String getPassed())")
  public void getNameAdvice(){
    LOGGER.info("Executing Advice on getPassword()");
  }

  @Before("execution(* com.acroynon.spring.service.*.get*())")
  public void getAllAdvice(){
    LOGGER.info("Service method getter called");
  }

}

Этот пост был первоначально опубликован на Этот пост был первоначально опубликован на

Оригинал: “https://dev.to/acroynon/single-responsibility-principle-srp-i9l”