Я слышал, как фразу бросают вокруг, и для меня аргументы звучат совершенно безумно (извините, если я здесь играю, это не мое намерение), как правило, это звучит примерно так:
Вы не хотите создавать абстракцию до того, как узнаете, каков общий случай, иначе (1) вы можете помещать в свои абстракции вещи, которые не принадлежат, или (2) пропускать важные вещи.
(1) Для меня это звучит так, как будто программист недостаточно прагматичен, они сделали предположение, что в финальной программе что-то не так, поэтому они работают с низким уровнем абстракции, проблема не в том, преждевременная абстракция, это преждевременная конкреция.
(2) Пропуск важных вещей - это одно, вполне возможно, что что-то пропущено из спецификации, которая впоследствии окажется важной, решение этой проблемы не в том, чтобы придумать собственный конкремент и тратить ресурсы, когда вы обнаружите, что вы угадал, это чтобы получить больше информации от клиента.
Мы должны всегда работать от абстракций до конкрементов, поскольку это самый прагматичный способ ведения дел, а не наоборот.
Если мы этого не сделаем, то мы рискуем неправильно понять клиентов и создать вещи, которые необходимо изменить, но если мы создаем только абстракции, которые клиенты определили на своем собственном языке, мы никогда не сталкиваемся с этим риском (по крайней мере, так близко, как вероятность принятия выстрел в темноте с некоторой конкретностью), да, возможно, клиенты изменят свое мнение о деталях, но абстракции, которые они использовали для первоначального сообщения того, что они хотят, как правило, остаются в силе.
Вот пример, скажем, клиент хочет, чтобы вы создали робота для упаковки предметов:
public abstract class BaggingRobot() {
private Collection<Item> items;
public abstract void bag(Item item);
}
Мы строим что-то из абстракций, которые использовал клиент, не вдаваясь в подробности с вещами, которых мы не знаем. Это чрезвычайно гибко, я видел, что это называется «преждевременная абстракция», когда на самом деле было бы более преждевременным предполагать, как была реализована упаковка, скажем, после обсуждения с клиентом, что они хотят, чтобы более чем один элемент был упакован одновременно , Чтобы обновить мой класс, все, что мне нужно, это изменить подпись, но для кого-то, кто начал снизу вверх, это может потребовать большой перестройки системы.
Нет такой вещи как преждевременная абстракция, есть только преждевременная конкреция. Что не так с этим утверждением? Где недостатки в моих рассуждениях? Спасибо.
Ответы:
По крайней мере, на мой взгляд, преждевременная абстракция довольно распространена, и это было особенно рано в истории ООП.
По крайней мере из того, что я увидел, возникла главная проблема - люди прочитали типичные примеры объектно-ориентированных иерархий. Им много говорили о том, что все готово для того, чтобы справиться с будущими изменениями, которые могут возникнуть (хотя не было особой причины полагать, что они это сделают). Еще одной темой, которая была распространена во многих статьях на какое-то время, были такие вещи, как утконос, который не поддается простым правилам о том, что «все млекопитающие такие» или «все такие птицы».
В результате мы получили код, который действительно должен был иметь дело, скажем, с записями сотрудников, но был тщательно написан, чтобы быть готовым, если вы когда-нибудь нанимали паукообразного или ракообразного.
источник
Важно помнить, что абстракция - это средство для достижения цели. Вы используете абстракцию для единообразного поведения в вашей программе и делаете добавление новых классов простым в тех случаях, когда вы ожидаете добавления новых классов, но только тогда, когда абстракция необходима в тот самый момент.
Вы не добавите абстракцию просто потому, что она может вам понадобиться (без реальной основы для того, чтобы думать, что вам понадобится добавлять новые классы в будущем). Правильная метафора здесь может быть сантехника. Надеюсь, вы согласитесь с тем, что труба с 6 направлениями, которая позволяет воде течь вверх / вниз, восток / запад, север / юг, была бы наиболее гибким типом трубопровода, который вы могли бы иметь. Вы можете теоретически использовать 6-направленную трубу в любом месте, где требуется труба, и блокировать ненужные направления, верно?
Если вы попытались устранить проблему с утечкой из вашей раковины и обнаружили, что все секции трубы были трубками с 6 направлениями, вам бы хотелось расстроиться из-за парня, который спроектировал его таким образом. Мало того, что вы не знаете, где проблема, но почти наверняка было бы более простым, просто начать с нуля, сделанного надлежащим образом.
Конечно, кодирование - это не сантехника, но метафора остается в силе. Абстракция похожа на использование этих 6-направленных частей трубы. Используйте их, если вы искренне уверены, что однажды в ближайшем будущем вам понадобится соединить трубы со всех 6 направлений. В противном случае абстракция - это просто усложнение, не сильно отличающееся от использования шаблона, в котором ничего не требуется, или использования класса бога, который пытается сделать все. Если он не используется и вряд ли когда-либо будет использован, вы в конечном итоге добавляете дополнительный класс даром.
По общему признанию, искусство написания программ очень очень абстрактно концептуально. Стоит просто отметить, что абстракции существуют не ради абстракции, а потому, что они практичны в некотором смысле. Если вы чувствуете необходимость использовать абстракцию, пусть будет так, но не просите меня проверить вашу сантехнику впоследствии. ;)
источник
class
центричны ... Даже если есть много классов, абстракция не ограничивается тем, чтобы их использовать / приносить пользу.Когда я много лет назад узнал об объектно-ориентированном анализе и проектировании, мы начали с простого описания системы, в которой нуждался клиент, на английском языке.
Просматривая это, любое существительное (или существительная фраза) будет рассматриваться как возможный класс. Любые глаголы (или глагольные фразы) будут потенциальными методами на классах. Так что «робот-упаковщик» может быть классом
BaggingRobot
. «Открыть сумку» может стать методомOpenBag
.После нескольких итераций это превратится в диаграмму классов.
На данный момент нет абстрактных классов. Заказчик не хочет абстрактной концепции упаковочного робота. Им нужен робот, который складывает вещи в мешки. Все классы являются конкретными и имеют набор методов.
Абстрактные классы вводятся только тогда, когда становится ясно, что:
Для меня «преждевременная абстракция» предполагает, что любой
BaggingRobot
должен наследовать от некоторыхBaseRobot
, и, что еще хуже, пытается разработать набор методов,BaseRobot
прежде чем вы даже узнаете, что является общим для всех роботов.источник
Это звучит так, будто вы хотите решить проблему, которой еще нет, и у вас нет веских оснований предполагать, что это произойдет, если вы просто не верите, что клиент ошибается в том, что он запрашивает. Если это так, я бы порекомендовал больше общения по поводу реализации решения угадывания, абстрактного или иного. Хотя может показаться безобидным просто «абстрагироваться» от определения класса и чувствовать себя в безопасности, зная, что вы можете расширить его позже, вы можете обнаружить, что вам это никогда не понадобится, или вы можете обнаружить, что расширяете его способами, которые чрезмерно усложняют дизайн. линия, абстрагируя неправильные вещи.
Следуя вашему примеру, представляете ли вы, что это сам робот , предметы, которые вы упаковываете, или метод , который изменится по линии?
Преждевременная абстракция на самом деле просто означает, что у вас нет веских оснований для выполнения абстракции, и, поскольку абстракции далеко не бесплатны во многих языках, вы можете столкнуться с накладными расходами без объяснения причин.
Редактировать Чтобы ответить на некоторые моменты из OP в комментариях, я обновляю это, чтобы прояснить и ответить так, чтобы не требовалась длинная цепочка комментариев, обращаясь к пунктам (1) и (2) более конкретно.
(Акцент мой). Предполагая, что в финальной программе будет что-то существующее, это не совсем то, что я вижу в вашем примере. Клиент попросил робота для упаковки товара. Это очень конкретный запрос, хотя и несколько неопределенный по своему языку. Клиенту нужен робот, который упаковывает вещи, поэтому вы создаете пару предметов
Ваша модель проста и точна, она соответствует требованиям, установленным заказчиком, не усложняя решение и не предполагая, что клиент хотел большего, чем он просил. Если при представлении этого они проясняют необходимость того, чтобы робот обладал взаимозаменяемой механикой упаковки, только тогда у вас будет достаточно информации для обоснования создания интерфейса или другого метода абстракции, поскольку теперь вы можете указать на конкретное значение , добавляемое к система через абстракцию.
Напротив, если вы начинаете с абстракции от чистого прагматизма, вы либо тратите время на создание отдельного интерфейса и реализацию его в конкретном виде, либо на создание абстрактного класса, или на любой другой способ абстракции, который вам нравится. Если потом окажется, что клиент удовлетворен этим, и дальнейшее расширение не требуется, вы потратили время и ресурсы напрасно и / или внесли дополнительные издержки и усложнили систему без выгоды.
Что касается (2), я согласен, что опущение важных вещей не является признаком преждевременной абстракции. Абстракция или нет, вы можете опустить что-то важное, и если это не будет найдено далеко за линией цепочки абстракций, не будет сложнее или проще разобраться в этом в любом случае.
Вместо этого я бы интерпретировал это как означающее, что любая абстракция рискует запутать вашу модель предметной области. Неправильная абстракция может сделать систему очень трудно рассуждать, так как вы создаете отношения, которые могут существенно повлиять на дальнейший рост модели домена и понимания домена. Вы рискуете опустить не важную информацию об абстрагируемой вещи , а о системе в целом , если ваша модель окажется не в той кроличьей норе.
источник