Пропускание структур данных 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, этот стиль совершенно естественен для небольших пользователей.