предметная область собственно элементы нашей бизнес логики или формат

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// предметная область
// собственно элементы нашей бизнес логики
// или формат данных нашего приложения
// именно в таком виде приложение видит данные
function Item(title) {
this.title = title;
}
Item.prototype = {
getPrice: function () {
return this.price;
},
setPrice: function (price) {
this.price = price;
},
setDiscount: function (discount) {
this.discount = discount;
},
getDiscount: function () {
return discount;
}
};
function OrderItem(item) {
this.item = item;
// запоминаем стоимость товара на момент покупки
// так как за время жизни заказа стоимость и скидка
// может несколько раз поменяться
this.price = item.getPrice() * item.getDiscount();
}
OrderItem.prototype = {
getPrice: function () {
return ;
},
getItem: function () {
return this.item;
}
}
function Order()
{
this.createdAt = new Date();
this.items = [];
}
Order.prototype = {
// вот тут я не уверен, следует ли создавать OrderItem внутри этого метода...
addItem: function (item) {
this.items.push(new OrderItem(item));
},
// согласно принципу "информационный эксперт" мы должны работать с данными
// там где они есть
// то есть создавать отдельный компонет для подсчета стоимости - ошибка
getPrice: function () {
return this.items.reduce(function (sum, orderItem) {
return sum + orderItem.getPrice();
}, 0);
}
}
// представление наших данных
// эти штуки знают о том как преобразовать данные из предметной области
// в требуемый формат.
// по хорошему у нас должны быть ItemView и OrderItemView но мне лень...
// так же этот класс должен содержать какие-то методы хелперы по преобразованию данных
// например цену оно должно брать именно из order item а не из item....
// но тут много вариантов и мне опять же лень... Все зависит от бизнес логики
// допустим у форм свои View
function OrderView(order, renderer) {
this.order = order;
// это какой-то сервис, который умеет рендрить шаблоны
// мы не знаем какие шаблоны и как оно работает
// мы только знаем что у него есть метод render
this.renderer = renderer;
}
OrderView.prototype = {
render: function () {
return this.renderer.render(this.order);
}
};
// сервисный слой
// хранилище наших заказов
// именно под этим кроется базы данных, апишки, кеши и прочее
// но суть именно такая, как тут. У нас есть некий объект-репозиторий
// который хранит внутри себя сущности
// снаружи систмы мы понятия не имеем что он сотворил с данными
// сериализовал, отправил на сервер, сохранил в локальной базе...
// нам нету дела. Зато если мы запросим у него объект
// он вернет нам его в том же состоянии, в котором мы его туда ложили
function OrderRepository(){
this.oriders = [];
}
OrderRepository.prototype = {
remove: function (order) {
// ...
},
find: function (id) {
// ...
},
save: function (order) {
// ...
}
}
// контроллер
// согласно все тем же принципам GRASP
// отвечает за обработку пользовательских сценариев
// вся работа с вводом/выводом пользовательских данных должна выполняться тут
// для удобства представим что у нас есть dependency injection
// который внедрит все зависимости по названию аргументов :)
function addOrderController(request, security, renderer, orderRepository, itemRepository) {
var user = security.getUser(),
item = itemRepository.find(requres.get('id'));
// обработкой и вывводом ошибок занимается фронт-контроллер.
// чем слоенее наш пирок, тем он гибче
if (!item) {
throw "Item not found";
}
var order = new Order();
order.addItem(item);
orderRepository.save(order);
// тут можно намного удобнее сделать, просто показал суть иерархии.
// Что это может быть не только шаблоны
return new Response((new OrderView(order, renderer)).render(), 200);
}