Пропускание структур данных JSON через сервер — это то, что я сейчас вижу больше. Документы JSON можно сохранить напрямую, используя AggregateOrientedDatabase или сериализованный большой объект в реляционной базе данных. Документы JSON могут также передаваться напрямую в веб-браузеры или использоваться для передачи данных на серверные средства визуализации страниц. Когда JSON используется таким образом, я слышу, как люди говорят, что использование объектно-ориентированного языка мешает, потому что JSON нужно переводить в объекты только для повторной визуализации — пустая трата усилий программирования [1] . Я согласен с пунктом об отходах, но я утверждаю, что это не проблема с объектами, а неспособность понять инкапсуляцию.
Давайте представим, что мы храним заказ как документ JSON и обрабатываем его с помощью незначительной обработки на стороне сервера, снова как JSON. Пример документа может быть таким:
{ "id": 1234,
"customer": "martin",
"items": [
{"product": "talisker", "quantity": 500},
{"product": "macallan", "quantity": 800},
{"product": "ledaig", "quantity": 1100}
],
"deliveries": [
{ "id": 7722,
"shipDate": "2013-04-19",
"items": [
{"product": "talisker", "quantity": 300},
{"product": "ledaig", "quantity": 500}
]
},
{ "id": 6533,
"shipDate": "2013-04-18",
"items": [
{"product": "talisker", "quantity": 200},
{"product": "ledaig", "quantity": 300},
{"product": "macallan", "quantity": 300}
]
}
]
}
Мы предполагаем, что у нас нет большой обработки на стороне сервера, но у нас есть некоторые. Давайте также предположим, что мы используем язык ОО. Наивным подходом может быть чтение в документе JSON, преобразование данных в соответствующий граф объектов (с заказами, линейными позициями и поставками), применение любой обработки и затем сериализация объекта графа в JSON для клиента.
Во многих из этих ситуаций лучшим способом для продолжения является сохранение данных в JSONish-форме, но все же обертывание их объектами для координации манипуляций. Большинство сред программирования предоставляют универсальные библиотеки, которые принимают документ и десериализуют его в общие структуры данных. Таким образом, документ JSON будет десериализован в структуру списков и словарей, документ XML — в дерево узлов XML. Затем мы можем взять эту общую структуру данных и поместить ее в поле объекта заказа — вот пример с Ruby и JSON.
class Order...
def initialize jsonDocument
@data = JSON.parse(jsonDocument)
end
Когда мы хотим манипулировать данными, мы можем, как обычно, определять методы объекта и реализовывать их, обращаясь к этой структуре данных.
class Order...
def customer
@data['customer']
end
def quantity_for aProduct
item = @data['items'].detect{|i| aProduct == i['product']}
return item ? item['quantity'] : 0
end
Это включает случаи с более сложной логикой. [2]
class Order...
def outstanding_delivery_for aProduct
delivered_amount = @data['deliveries'].
map{|d| d['items']}.
flatten.
select{|d| aProduct == d['product']}.
inject(0){|res, d| res += d['quantity']}
return quantity_for(aProduct) - delivered_amount
end
Встроенный документ может быть дополнен перед отправкой клиенту.
class Order...
def enrich
@data['earliestShipDate'] =
@data['deliveries'].
map{|d| Date.parse(d['shipDate'])}.
min.
to_s
end
При необходимости вы можете сформировать похожие объекты на поддеревьях внедренного документа.
class Order...
def deliveries
@data['deliveries'].map{|d| Delivery.new(d)}
end
class Delivery...
def initialize hash
@data = hash
end
def ship_date
Date.parse(@data['shipDate'])
end
Здесь следует опасаться, что такие обертки объектов не совсем такие же, как обычные объекты. Объекты доставки, возвращенные в приведенном выше фрагменте кода, не имеют той же семантики равенства, которую вы ожидаете от объектов, расположенных в более обычной структуре.
Несмотря на сравнительную редкость, внедренный документ хорошо вписывается в объектную ориентацию. Точка инкапсулированных данных — это скрытие структуры данных, так что пользователи объекта не знают или не заботятся о внутренней структуре заказа.
Те, кто знаком с функциональным программированием, распознают стиль передачи общей структуры данных через ряд функций — вы можете думать об объекте как о предоставлении пространства имен для манипулирования общими структурами данных.
Приятным моментом для встроенного документа является то, что вы предоставляете документ в той же форме, в которой вы получаете его из хранилища данных, но все же хотите выполнить некоторые манипуляции с этими данными. Если вам не требуется доступ к содержимому документа JSON, нет необходимости даже десериализовать его в общую структуру данных. Для объекта заказа требуется только конструктор и метод для возврата его представления JSON. С другой стороны, по мере того, как вы будете больше работать с данными — больше логики на стороне сервера, трансформирующейся в разные представления — тогда стоит подумать, проще ли превратить данные в граф объектов.
1: Некоторые могут возразить, что это тоже пустая трата компьютерных усилий — хотя я был бы удивлен, если бы это было важно. Я бы, конечно, не принял аргумент производительности против преобразования в граф объектов, если бы он не сопровождался измерениями — как любой аргумент производительности .
2: обратите внимание на цепочку CollectionLambdas в этом методе. Одно из моих домашних раздражений — слышать, как некоторые функциональные фанаты говорят, что этот стиль кода не является объектно-ориентированным. Хотя это может показаться чуждым для тех, кто имеет опыт работы с C ++ / Java, этот стиль совершенно естественен для небольших пользователей.