Представьте, что ваши клиенты хотят иметь возможность добавлять новые свойства (например, цвета) к продукту в своем интернет-магазине в своей CMS.
Вместо того, чтобы иметь свойства как поля:
class Car extends Product {
protected String type;
protected int seats;
}
Вы, вероятно, в конечном итоге сделать что-то вроде:
class Product {
protected String productName;
protected Map<String, Property> properties;
}
class Property {
protected String name;
protected String value;
}
То есть создание собственной системы типов поверх существующей. Мне кажется, что это можно рассматривать как создание языка, специфичного для домена, или нет?
Является ли этот подход известным шаблоном дизайна? Вы бы решили проблему по-другому? Я знаю, что есть языки, где я могу добавить поле во время выполнения, но как насчет базы данных? Вы бы предпочли добавить / изменить столбцы или использовать что-нибудь, как показано выше?
Спасибо за уделенное время :).
Ответы:
Поздравляем! Вы только что совершили кругосветное плавание на языке программирования / системе типов, прибыв на другой край света, откуда вы отправились. Вы только что приземлились на границе динамического языка / прототипа объекта земли!
Многие динамические языки (например, JavaScript, PHP, Python) позволяют расширять или изменять свойства объекта во время выполнения.
В крайнем случае это язык на основе прототипов, такой как Self или JavaScript. У них нет занятий, строго говоря. Вы можете делать вещи, которые выглядят как объектно-ориентированное программирование на основе классов, с наследованием, но правила значительно упрощены по сравнению с более четко определенными языками на основе классов, такими как Java и C #.
Языковые языки, такие как PHP и Python, живут посередине. У них есть регулярные идиоматические системы на основе классов. Но атрибуты объекта могут быть добавлены, изменены или удалены во время выполнения - хотя и с некоторыми ограничениями (например, «кроме встроенных типов»), которых вы не найдете в JavaScript.
Большим компромиссом для этого динамизма является производительность. Забудьте, насколько сильно или слабо типизирован язык, или насколько хорошо его можно скомпилировать в машинный код. Динамические объекты должны быть представлены в виде гибких карт / словарей, а не простых структур. Это добавляет накладные расходы на каждый доступ к объекту. Некоторые программы идут на все, чтобы уменьшить эти издержки (например, с помощью фантомного назначения kwarg и основанных на слотах классов в Python), но дополнительные накладные расходы обычно равны курсу и стоимости приема.
Возвращаясь к своему дизайну, вы прививаете возможность иметь динамические свойства в подмножестве ваших классов.
Product
Может иметь переменные атрибуты; по-видимому,Invoice
илиOrder
бы и не мог. Это не плохой путь. Это дает вам гибкость, позволяющую варьировать, где вам это необходимо, оставаясь при этом в строгой, дисциплинированной системе языков и типов. С другой стороны, вы несете ответственность за управление этими гибкими свойствами, и вам, вероятно, придется делать это с помощью механизмов, которые немного отличаются от более собственных атрибутов.p.prop('tensile_strength')
а неp.tensile_strength
, например,p.set_prop('tensile_strength', 104.4)
а неp.tensile_strength = 104.4
, Но я работал со многими программами на Pascal, Ada, C, Java и даже на динамических языках, которые использовали именно такой доступ для получения-установки для нестандартных типов атрибутов; подход явно работоспособен.Между прочим, это напряжение между статическими типами и очень разнообразным миром чрезвычайно распространено. Аналогичная проблема часто наблюдается при разработке схемы базы данных, особенно для реляционных и предреляционных хранилищ данных. Иногда это делается путем создания «супер-строк», которые содержат достаточно гибкости, чтобы содержать или определять объединение всех воображаемых вариаций, а затем вводить любые данные, которые попадают в эти поля. WordPress
wp_posts
таблица , например, имеет поле , такие какcomment_count
,ping_status
,post_parent
иpost_date_gmt
что только интересно при некоторых обстоятельствах, и что на практике часто гаснуть. Другой подход - это очень запасной, нормализованный столwp_options
, похожий на вашProperty
учебный класс. Хотя это требует более явного управления, элементы в нем редко бывают пустыми. Объектно-ориентированные базы данных и базы данных (например, MongoDB) часто легче справляются с изменением параметров, поскольку они могут создавать и задавать атрибуты практически по желанию.источник
Мне нравится вопрос, мои два цента:
Ваши два подхода радикально отличаются:
В C ++ многие использовали бы std :: map of boost :: option для достижения сочетания обоих.
Отступление: обратите внимание, что некоторые языки, такие как C #, позволяют динамически создавать типы. Что может быть хорошим решением для общей проблемы добавления участников динамически. Однако «модификация / добавление» типов после компиляции приводит к повреждению самой системы типов и делает ваши «измененные» типы практически бесполезными (например, как бы вы получили доступ к таким добавленным свойствам, поскольку вы даже не знаете, что они существуют? Единственный разумный способ - быть систематическим отражением каждого объекта ... заканчивая чисто динамическим языком _ вы можете обратиться к ключевому слову "dynamic" .NET)
источник
Создание типа во время выполнения звучит намного сложнее, чем просто создание слоя абстракции. Распространено создание абстракции для разделения систем.
Позвольте мне показать пример из моей практики. Московская биржа имеет торговое ядро Plaza2 с API трейдера. Трейдеры пишут свои программы для работы с финансовыми данными. Проблема в том, что эти данные очень большие, сложные и подвержены изменениям. Это может измениться после того, как введен новый финансовый продукт или изменен круг клиринга. Характер будущих изменений не может быть предсказан. Буквально, это может меняться каждый день, и плохие программисты должны редактировать код и выпускать новую версию, а злые трейдеры должны пересматривать свои системы.
Очевидное решение - спрятать весь финансовый ад за абстракцию. Они использовали хорошо известную абстракцию таблиц SQL. Большая часть их ядра может работать с любой действительной схемой, так же как программное обеспечение трейдера может динамически анализировать схему и выяснить, совместима ли она с их системой.
Возвращаясь к вашему примеру, нормально создавать абстрактный язык перед некоторой логикой. Это может быть «свойство», «таблица», «сообщение» или даже человеческий язык, но обратите внимание на недостатки этого подхода:
источник
В XML и HTML это будут атрибуты узла / элемента. Я также слышал, что они называются расширенными свойствами, парами имя / значение и параметрами.
Вот так я бы решил проблему, да.
В некотором смысле база данных будет похожа на Java. В песо-sql:
Это будет соответствовать Java
Обратите внимание, что в классе Property нет необходимости, поскольку карта хранит имя в качестве ключа.
Я пробовал добавить / изменить столбец, и это был кошмар. Это может быть сделано, но вещи продолжали идти синхронно, и я никогда не заставлял это работать хорошо. Структура таблицы, которую я изложил выше, была гораздо более успешной. Если вам нужно сделать поиск и заказ, рассмотрите используя атрибуты таблицы для каждого типа данных (
date_attributes
,currency_attributes
и т.д.) или добавив некоторые свойства , как старые добрые столбцы базы данных в таблице продуктов. Отчеты часто гораздо проще писать в столбцах базы данных, чем в подстолях.источник