Сегодня я читал книгу под названием «Чистый код» и наткнулся на абзац, где автор говорил об уровнях абстракции для функции, он классифицировал некоторый код как низкий / средний / высокий уровень абстракции.
Мой вопрос: каковы критерии определения уровня абстракции?
Я цитирую абзац из книги:
Чтобы убедиться, что наши функции выполняют «одну вещь», мы должны убедиться, что все операторы в нашей функции находятся на одном уровне абстракции. Легко увидеть, как листинг 3-1 нарушает это правило. Там есть понятия, которые находятся на очень высоком уровне абстракции, такие как getHtml (); другие, которые находятся на промежуточном уровне абстракции, такие как: String pagePathName = PathParser.render (pagePath); и еще другие, которые находятся на удивительно низком уровне, такие как: .append ("\ n").
источник
Ответы:
Автор объясняет, что в подразделе «Чтение кода сверху вниз» части, в которой говорится об абстракциях (шахта иерархического отступа):
Код, который согласуется с этим, будет выглядеть примерно так:
И так далее. Каждый раз, когда вы углубляетесь в иерархию функций, вы должны менять уровни абстракции. В приведенном выше примере
IncludeSetups
,IncludeTestPageContent
иIncludeTeardowns
все на том же уровне абстракции.В примере, приведенном в книге, автор предлагает разбить большую функцию на более мелкие, которые очень специфичны и выполняют только одну функцию. Если все сделано правильно, рефакторированная функция будет выглядеть аналогично приведенным здесь примерам. (Реорганизованная версия приведена в листинге 3-7 в книге.)
источник
Я думаю, чтобы понять этот вопрос, вам нужно понять, что такое абстракция. (Я слишком ленив, чтобы найти формальное определение, поэтому я уверен, что скоро начну испытывать затруднения, но здесь ...) Абстракция - это когда вы берете сложный предмет или сущность и скрываете большинство его деталей. при этом раскрывая функциональность, которая до сих пор определяет суть этого объекта.
Я считаю, что пример, который книга дала вам, был домом. Если вы внимательно посмотрите на дом, вы увидите, что он сделан из досок, гвоздей, окон, дверей ... Но мультфильм, изображающий дом рядом с фотографией, все еще остается домом, хотя его и не хватает. многие из этих деталей.
То же самое с программным обеспечением. Всякий раз, когда вы программируете, как советует книга, вы должны думать о своем программном обеспечении как о слоях. Данная программа может легко иметь более ста слоев. Внизу у вас могут быть инструкции по сборке, которые выполняются на процессоре, на более высоком уровне эти инструкции могут быть объединены для формирования подпрограмм дискового ввода-вывода, но на более высоком уровне вам не нужно работать с диском I / O напрямую, потому что вы можете использовать функции Windows для простого открытия / чтения / записи / поиска / закрытия файла. Все это абстракции еще до того, как вы перейдете к собственному коду приложения.
Внутри вашего кода уровни абстракции продолжаются. Возможно, у вас есть процедуры обработки строк / сети / данных более низкого уровня. На более высоком уровне вы можете объединить эти подпрограммы в подсистемы, которые определяют управление пользователями, уровень пользовательского интерфейса, доступ к базе данных. Еще один уровень, на котором эти подсистемы могут быть объединены в серверные компоненты, которые собираются вместе, чтобы стать частью более крупной корпоративной системы.
Ключом к каждому из этих уровней абстракции является то, что каждый из них скрывает детали, представленные предыдущим уровнем (уровнями), и представляет очень чистый интерфейс, который будет использоваться следующим уровнем вверх. Чтобы открыть файл, вам не нужно знать, как писать отдельные сектора или какие аппаратные прерывания обрабатываются. Но если вы начнете перемещаться по цепочке уровня абстракции, вы определенно сможете проследить от вызова функции Write (), вплоть до точной инструкции, отправляемой контроллеру жесткого диска.
Автор говорит вам, что когда вы определяете класс или функцию, подумайте, какой вы слой. Если у вас есть класс, который управляет подсистемами и объектами пользователя, тот же класс не должен выполнять низкоуровневые манипуляции со строками или содержать целый набор переменных только для выполнения вызовов сокетов. Это было бы нарушением пересечения уровней абстракции, а также наличия одного класса / функции, делающей только одно (SRP - принцип единой ответственности).
источник
Уровень абстракции должен быть очевидным. Это абстрактно, если это часть проблемной области, а не часть языка программирования. Трудно быть более ясным, чем "очень абстрактные" == "не реальные" == "проблемные области". И "не абстрактно == конкретная == часть языка". Это должно быть тривиально, чтобы определить уровень абстракции. Там не должно быть никакой тонкости вообще.
.append("\n")
не абстрактно. Он просто помещает символ в строку. Это было бы конкретно. Не абстрактно.String pagePathName = PathParser.render(pagePath);
имеет дело со строками. Конкретные вещи. Частично о конкретных особенностях языка программирования. Частичная работа с абстрактными понятиями «путь» и «парсер».getHtml();
Аннотация. Имеет дело с "Разметкой" и вещами, которые не являются тривиальными, конкретными, языковыми особенностями.Абстракт == не языковая особенность.
Конкретный == языковая особенность.
источник
Я думаю, что уровень абстракции прост ... если строка кода напрямую не реализует единственную ответственность метода, это другой уровень абстракции. Например, если мой метод называется SaveChangedCustomers () и в качестве параметра принимает список ВСЕХ клиентов, единственной обязанностью является сохранение всех клиентов в списке, которые были изменены:
Часто вместо вызова метода CustomerIsChanged () вы найдете логику, чтобы определить, изменился ли клиент, встроенный в цикл foreach. Определение того, изменилась ли запись клиента, НЕ является обязанностью этого метода! Это другой уровень абстракции. Но что, если логика для такого определения - всего одна строка кода? Это не важно !!! Это другой уровень абстракции и должен быть за пределами этого метода.
источник