Добавил небольшую заметку о полях-дискриминаторах
This commit is contained in:
parent
aaffa8b917
commit
096af09062
@ -11,6 +11,7 @@ sculpin_content_types:
|
||||
singular_name: album
|
||||
layout: internal
|
||||
permalink: albums/:basename/
|
||||
publish_drafts: false
|
||||
enabled: true
|
||||
taxonomies:
|
||||
- tags
|
||||
@ -20,6 +21,7 @@ sculpin_content_types:
|
||||
singular_name: article
|
||||
layout: article
|
||||
permalink: articles/:year-:month-:day-:basename/
|
||||
publish_drafts: false
|
||||
enabled: true
|
||||
taxonomies:
|
||||
- tags
|
||||
|
122
source/_articles/2020-06-27-type-discriminant.md
Normal file
122
source/_articles/2020-06-27-type-discriminant.md
Normal file
@ -0,0 +1,122 @@
|
||||
---
|
||||
title: О полях-дискриминаторах
|
||||
description: Заметка о том, как записывать конфигурацию для сложных объектов
|
||||
keywords: [чистый код, дискриминатор, php, конфигурация]
|
||||
---
|
||||
|
||||
Поля-дискриминаторы - это удобный прием для обработки нескольких типов
|
||||
данных со схожей структурой.
|
||||
|
||||
Лучше начать с примера.
|
||||
|
||||
Допустим, у нас есть объект-фильтр для целых чисел. Можно применить фильтр
|
||||
к последовательности чисел и получить новую последовательность.
|
||||
Его параметры выглядят следующим образом:
|
||||
|
||||
```json
|
||||
{
|
||||
"from": 0,
|
||||
"to": 10
|
||||
}
|
||||
```
|
||||
|
||||
Отлично.
|
||||
Фильтр пропустит только числа от 0 до 10.
|
||||
По такой конфигурации без проблем можно создать объект.
|
||||
|
||||
Теперь добавим второй фильтр - он будет отсекать нечетные числа.
|
||||
|
||||
```json
|
||||
{
|
||||
"odd": false
|
||||
}
|
||||
```
|
||||
|
||||
## Создаем фильтр на основе структуры
|
||||
|
||||
Теперь есть два фильтра, и нужно понимать какой их них создать.
|
||||
Простое и наивное решение - смотреть на структуру полей.
|
||||
Если есть поле `odd`, то фильтр нечетных чисел, иначе - фильтр по диапазону.
|
||||
|
||||
```php
|
||||
if (isset($config['odd'])) {
|
||||
// фильтр нечетных чисел
|
||||
} else {
|
||||
// фильтр диапазона
|
||||
}
|
||||
```
|
||||
|
||||
У этого решения масса недостатков.
|
||||
Например, если поле `odd` понадобится двум фильтрам сразу, то условие усложнится.
|
||||
Или появятся поля с разными названиями, но одинаковым смыслом.
|
||||
|
||||
## Добавляем поле-дискриминатор
|
||||
|
||||
Решение проблемы в добавление специального поля, в котором содержится имя фильтра.
|
||||
Назовем это поле `type`. Тогда конфигурации фильтров будут выглядеть следующим образом:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "range",
|
||||
"from": 0,
|
||||
"to": 10
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "odd_control",
|
||||
"odd": false
|
||||
}
|
||||
```
|
||||
|
||||
Поле `type` - это и есть поле-дискриминатор.
|
||||
По нему можно точно определить какой фильтр перед нами.
|
||||
|
||||
```php
|
||||
switch ($config['type']) {
|
||||
case 'range':
|
||||
// фильтр диапазона
|
||||
break;
|
||||
case 'odd_control':
|
||||
// фильтр нечетных чисел
|
||||
break;
|
||||
default:
|
||||
throw new \LogicException(sprintf(
|
||||
'Unknown filter type "%s"', $config['type']));
|
||||
}
|
||||
```
|
||||
|
||||
## Выделить зависимые поля
|
||||
|
||||
Решение еще можно улучшить.
|
||||
Сейчас на одном уровне в структуре конфига есть и обязательные поля, и необязательные поля.
|
||||
Мы можем перенести все необязательные поля на дополнительный уровень,
|
||||
например, в поле `params`.
|
||||
Эти поля необязательны для всей конфигурации, но обязательны для конкретного фильтра.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "range",
|
||||
"params": {
|
||||
"from": 0,
|
||||
"to": 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Что дает такой маневр?
|
||||
На верхнем уровне конфигурации у нас будет постоянная структура.
|
||||
Поле `params` можно до определенного времени рассматривать как черный ящик,
|
||||
просто зная, что это некий словарь параметров.
|
||||
Когда будет понятно какой фильтр создавать, тогда этот набор параметров
|
||||
послужит базой для создания объекта-фильтра.
|
||||
|
||||
## Заключение
|
||||
|
||||
- Если структура конфигурации предполагает создание нескольких разных объектов,
|
||||
то лучше использовать специальное поле-дискриминатор для точного указания
|
||||
типа создаваемого объекта.
|
||||
- Все поля, которые зависят от типа, лучше перенести на дополнительный уровень,
|
||||
тем самым сохранив структуру верхнего уровня постоянной (на верхнем уровне
|
||||
будет всегда один и тот же набор полей).
|
5
tools/mkpost
Executable file
5
tools/mkpost
Executable file
@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eux
|
||||
|
||||
touch "source/_articles/$(date +'%Y-%m-%d')-$1.md"
|
Loading…
Reference in New Issue
Block a user