Додавання поля до класу під час виконання - шаблон дизайну


15

Уявіть, що ваш клієнт хоче мати можливість додати нову властивість (наприклад, колір) до продукту у своєму магазині у своїй 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;
}

Тобто створення системи власного типу поверх існуючої. Мені здається, що це можна було б сприймати як створений доменний мов, чи не міг?

Чи є такий підхід відомою схемою дизайну? Ви вирішили б проблему інакше? Я знаю, що існують мови, в які я можу додати поле під час виконання, але що робити з базою даних? Ви бажаєте додати / змінити стовпці або використати щось, як показано вище?

Спасибі за ваш час :).



Не впевнений, якою мовою ви користуєтесь, але якщо це C #, ви можете використовувати динамічний тип, який, в основному, зберігає KVP у словнику начебто як те, що ви робите на продуктах, і дозволяє вам просто дотримуватися властивостей без необхідності безпосередньо додавати їх до колекція як колекція. Однак у вас не буде сильного набору тексту. Я знаю, що ви попросили модель дизайну, але я не думаю, що вам знадобиться щось складне для їх використання. msdn.microsoft.com/en-us/magazine/gg598922.aspx
Тоні

Тоні: Я тут використовую Java, але вважай це псевдо куде :). Чи дозволить мені C # зберігати цей динамічний об’єкт у базі даних? Я сумніваюся в цьому, оскільки база даних повинна знати структуру даних наперед.
Філіп

Існує модель дизайну стану a-la Gang-of-Four, завдяки якій об’єкт, здається, змінює свій тип або клас під час виконання. Іншими альтернативами є модель дизайну спостерігача або шаблон дизайну проксі
Нікос М.

1
Чому б не просто використовувати тип даних карти? У БД він може бути представлений як {id} + {id, ключ, значення}, якщо ви не вимагаєте виконання.
Shadows In Rain

Відповіді:


4

Вітаємо! Ви щойно об’їхали глобус системи / мови програмування, приїхавши на інший бік світу, звідки ви вирушили. Ви щойно приземлилися на межі об'єктів на динамічній мові / прототипі!

Багато динамічних мов (наприклад, 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) часто легше розбираються зі зміною параметрів, оскільки вони можуть створювати та встановлювати атрибути майже за власним бажанням.


0

Мені подобається питання, мої два центи:

Ваші два підходи кардинально відрізняються:

  • Перший - OO ans, сильно набраний, але не розширюваний
  • Другий - слабо набраний (рядок інкапсулює що-небудь)

У C ++ багато хто використовує варіант std :: map boost :: для досягнення суміші обох.

Дигресія: Зауважте, що деякі мови, наприклад C #, дозволяють динамічно створювати типи. Що може бути гарним рішенням для загального питання щодо динамічного додавання членів. Однак "модифікація / додавання" типів після компіляції пошкоджує саму систему типів і робить ваші "модифіковані" типи майже марними (наприклад, як би ви отримали доступ до таких доданих властивостей, оскільки ви навіть не знаєте, що вони існують? Єдиний розумний спосіб би бути систематичним відображенням над кожним об’єктом ... закінчуючи чистою динамічною мовою _ ви можете посилатися на "динамічне" .NET ключове слово)


Створення типів під час виконання швів цікаво, але занадто екзотично для мене (я програмую на Java). Таке рішення не спрацювало, якби я хотів би зберігати об’єкт у databse, який завжди сильно набраний, я вірю. Запропоноване мною слабо типове рішення може легко зберігатися в базі даних.
Філіп

0

Створення типу під час виконання звучить набагато складніше, ніж просто створення шару абстракції. Дуже звичайно створювати абстракцію для роз'єднання систем.

Дозвольте показати приклад зі своєї практики. Московська біржа має торговельне ядро ​​під назвою Plaza2 з API торговця. Торговці записують свої програми для роботи з фінансовими даними. Проблема полягає в тому, що ці дані дуже величезні, складні та сильно піддаються змінам. Він може змінитися після введення нового фінансового продукту або зміни клітини клірингу. Характер майбутніх змін неможливо передбачити. Буквально це може змінюватися щодня, і бідні програмісти повинні редагувати код і випускати нову версію, а розлючені трейдери повинні переглянути свої системи.

Очевидним рішенням є приховати все фінансове пекло за абстракцією. Вони використовували відомі абстракції таблиць SQL. Найбільша частина їх ядра може працювати з будь-якою дійсною схемою, так само як програмне забезпечення трейдера може динамічно розбирати схему та з'ясовувати, чи сумісна вона з їх системою.

Повертаючись до свого прикладу, нормально створювати абстрактну мову перед певною логікою. Це може бути "властивість", "таблиця", "повідомлення" або навіть людська мова, але зверніть увагу на недоліки такого підходу:

  • Більше коду для синтаксичного розбору та перевірки (і більше часу поза вихідним курсом). Все, що компілятор зробив для вас зі статичним набором тексту, який ви повинні робити під час виконання.
  • Більше документації з повідомленнями, таблицями чи іншими примітивами. Вся складність переходить від коду до якоїсь схеми чи стандарту. Ось приклад згаданої схеми фінансового пекла: http://ftp.moex.com/pub/FORTS/Plaza2/p2gate_en.pdf (десятки сторінок таблиць)

0

Чи є такий підхід відомою схемою дизайну?

У XML та HTML це будуть атрибути до вузла / елемента. Я також чув, як вони називали розширені властивості, пари імен / значень і параметри.

Ви вирішили б проблему інакше?

Саме так я вирішив би проблему, так.

Я знаю, що існують мови, в які я можу додати поле під час виконання, але що робити з базою даних?

База даних буде подібною до Java, в деяких сенсах. У песудо-sql:

TABLE products
(
    product_name VARCHAR(50),
    product_id INTEGER AUTOINCREMENT
)

TABLE attributes
(
    product_id INTEGER,
    name VARCHAR(50),
    value VARCHAR(2000)
)

Це відповідало б Java

class Product {
   protected String productName;
   protected Map<String, String> properties;
}

Зверніть увагу, що клас власності не потрібен, оскільки Map зберігає ім'я як ключове.

Ви бажаєте додати / змінити стовпці або використати щось, як показано вище?

Я спробував додавати / змінювати колонку, і це був кошмар. Це можна зробити, але все не виходило з синхронізації, і я ніколи не змушував його працювати добре. Структура таблиці, яку я окреслив вище, була набагато успішнішою. Якщо вам потрібно зробити пошук і замовлення, розгляньте використовуючи атрибути таблиці для кожного типу даних ( date_attributes, currency_attributesі т.д.) або додавши деякі властивості , як старі добрі стовпці бази даних в таблиці продуктів. Звіти часто набагато простіше писати в стовпці бази даних, а потім під таблиці.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.