Pull to refresh

Comments 10

UFO just landed and posted this here

Предположим, у нас есть класс FileManager, который отвечает за чтение и запись данных в файл. Однако, в соответствии с SRP, этот класс должен быть ответственен только за одну обязанность. Разделим его функционал на два класса: FileReader и FileWriter

Нет, предметная область одинаковая, не должен. Но может. Чисто ООП-шные mind games и метания юного Вертера. Вот обработку файлов и бизнес-логики уже не стоит смешивать. Разработчики этого часто разные люди, придется одному вмешиваться в работу другого. А если один человек, то придется переключать контекст проблемы в голове, что в сущности то же что и как 2 человека работают.

Предположим, у нас есть класс FileManager, который отвечает за чтение и запись данных в файл. Однако, в соответствии с SRP, этот класс должен быть ответственен только за одну обязанность. Разделим его функционал на два класса: FileReader и FileWriter

Что такое критерий сортировки? Алгоритм? Ну что ж, можно алгоритм указывать в виде параметра, а можно создать несколько функций сортировки. В данном случае необходимости в полиморфизме не вижу.

Принцип подстановки Лисков

Очень узкий взгляд, из всех вариантов полиморфизма указан только полиморфизм наследования, плохой вариант.

public class Shape { public virtual void Draw() { // Default implementation } }

public class Circle : Shape { public override void Draw() { // Specific implementation for drawing a circle } }

public class Rectangle : Shape { public override void Draw() { // Specific implementation for drawing a rectangle } }

Вот другие типы полиморфизма, реализующие LSP

  1. Ad-hoc Polymorphism:

    • public class Calculator 
      {
      public int Add(int a, int b) 
      { 
          return a + b; 
      }
                               
      public double Add(double a, double b)
      {
          return a + b;
      }
      

      }

    • This example showcases method overloading in C#, allowing different implementations of the Add method to be selected based on the types of the arguments, aligning with LSP by enabling the substitution of objects of subclasses for objects of the superclass without impacting the correctness of the program.

  2. Parametric Polymorphism:

    • Example:

      public class List <T>
      {
      // Implementation of a generic list
      }

    • C# supports parametric polymorphism through generic classes like List, enabling the reuse of code with different types without affecting the correctness of the program, in line with LSP.

  3. Inclusion Polymorphism:

    • ...

Виды полиморфизма

Ad hoc полиморфизм (специализированный полиморфизм)

-Перегрузка функций (методов)

-Перегрузка операторов

Полиморфизм подтипов

-Полиморфизм включения

Параметрический полиморфизм

-Параметрические методы

-Параметрические типы

ну чего-то устал уже душнить...

большое спасибо, исправлю

UFO just landed and posted this here

Принцип единственной ответственности (SRP) - это принцип,
сформулированный Робертом Мартином (Uncle Bob), который утверждает, что
каждый объект должен иметь одну и только одну причину для изменения, то
есть каждый объект должен быть ответственен за выполнение только одной
задачи или иметь только одну обязанность.

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

Но тогда в любом объекте должны содержаться либо только одна единственная структура данных, либо только один единственный метод....

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

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

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

" remember that the reasons for change are people. It is people who request changes." последний параграф в https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html

"Принцип единственной ответственности (SRP) - это принцип, сформулированный Робертом Мартином (Uncle Bob), который утверждает, что каждый объект должен иметь одну и только одну причину для изменения, то есть каждый объект должен быть ответственен за выполнение только одной задачи или иметь только одну обязанность." - вот вы тоже вводите людей в заблуждение. Мартин подчёркивает, что дело не в обязанности, а ответственности перед кем-то. Строго говоря, у каждого работника только один начальник. У сотрудника может быть несколько зон ответственности и обязанностей, но причиной меняться может быть только один (человек, класс, сервис).

В целом хорошая статья, но сколько можно наступать на грабли антипаттерна Rectangle-Square ( он же Ellipse-Circle)!

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

Класс Квадрат не является ПО ПОВЕДЕНИЮ Прямоугольником! Автор, как и многие, путает состояние и поведение. Наследование необходимо для получения классом-наследником от родителя абстракции поведения - и написания особенностей реализации этой абстракции. А распространённая в антипаттерне Rectangle-Square ошибка - ограничение (сужение) поведения родителя с помощью фиксации его состояния. Для борьбы с этим антипаттерном создатели Java для обозначения наследования ввели слово extends ("расширяет"), чтобы ошибка задания наследника

class Square extends Rectangle

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

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

class Rectangle extends Square - так наследовать тоже нельзя по упомянутым выше причинам сравнения поведения экземпляров этих классов, хотя синтаксис Java на эту ошибку не указывает.

Самый простой способ бороться с подобным ошибками построения иерархий наследования - наследовать только от абстрактных классов. Ведь при наследовании необходимо наследовать только абстракцию поведения, и только для реализации полиморфизма. А наследование особенностей реализации, нарушающее принцип инкапсуляции - мина замедленного действия. Заранее неизвестно, когда и при каких обстоятельствах она рванёт.

В последнем примере у вас висящий указатель:

void setJobTitle(const std::string& title) {
    // Создаем объект Job с переданным названием должности
    Job newJob(title);
	
    // Передаем только необходимую информацию (название должности)
    setJob(&newJob);
}

Sign up to leave a comment.

Articles