Я думаю, что вы могли бы найти мой пост в блоге о дырявых абстракциях полезным. Вот соответствующий фон:
Абстракция - это механизм, помогающий взять то, что является общим среди набора связанных фрагментов программы, устранить их различия и позволить программистам работать непосредственно с конструкцией, представляющей эту абстрактную концепцию. Эта новая конструкция (фактически) всегда имеет параметризацию : средство для настройки использования конструкции в соответствии с вашими конкретными потребностями.
Например, List
класс может абстрагироваться от деталей реализации связного списка - где вместо того, чтобы думать в терминах манипулирования next
и previous
указателей, вы можете думать об уровне добавления или удаления значений в последовательности. Абстракция является важным инструментом для создания полезных, богатых, а иногда и сложных функций из гораздо меньшего набора более примитивных концепций.
Абстракция связана с инкапсуляцией и модульностью, и эти понятия часто неправильно понимают.
В этом List
примере инкапсуляция может использоваться, чтобы скрыть детали реализации связанного списка; в объектно-ориентированном языке, например, вы можете сделать next
и previous
указатели частным, где только реализация списка разрешен доступ к этим полям.
Инкапсуляции недостаточно для абстракции, потому что это не обязательно означает, что у вас есть новая или другая концепция конструкций. Если бы весь List
класс давал вам методы доступа в стиле ' getNext
' / ' setNext
', он инкапсулировал бы вас в подробности реализации (например, называли ли вы поле ' prev
' или ' previous
'? Каков его статический тип?), Но это будет иметь очень низкую степень абстракции.
Модульность связана с сокрытием информации : стабильные свойства указываются в интерфейсе, и модуль реализует этот интерфейс, сохраняя все детали реализации в модуле. Модульность помогает программистам справляться с изменениями, потому что другие модули зависят только от стабильного интерфейса.
Сокрытию информации способствует инкапсуляция (чтобы ваш код не зависел от нестабильных деталей реализации), но инкапсуляция не требуется для модульности. Например, вы можете реализовать List
структуру в C, выставляя « next
» и « prev
» указатели на мир, но и обеспечивают интерфейс, содержащий initList()
,addToList()
иremoveFromList()
функции. При условии соблюдения правил интерфейса вы можете гарантировать, что определенные свойства будут всегда сохраняться, например, гарантировать, что структура данных всегда находится в допустимом состоянии. [Классическая статья Парнаса о модульности, например, была написана с примером в сборке. Интерфейс является контрактом и формой сообщения о дизайне, он не обязательно должен быть механически проверен, хотя мы сегодня на это полагаемся.]
Хотя такие термины, как абстрактный, модульный и инкапсулированный, используются в качестве положительных описаний дизайна, важно понимать, что наличие любого из этих качеств автоматически не дает хорошего дизайна:
Если алгоритм n ^ 3 «красиво инкапсулирован», он все равно будет работать хуже, чем улучшенный алгоритм n log n.
Если интерфейс поддерживает определенную операционную систему, ни одно из преимуществ модульного дизайна не будет реализовано, когда, скажем, видеоигру нужно перенести с Windows на iPad.
Если созданная абстракция предоставляет слишком много несущественных деталей, она не сможет создать новую конструкцию со своими собственными операциями: это просто будет другое имя для той же вещи.