Архитектура клиент/сервер
Наиболее важным вопросом реализации архитектуры клиент/сервер является не столько вопрос о том, где будет проведена граница между этими двумя частями, сколько о том, как разумно произвести это разделение. Возвращаясь к первоосновам, ответ на этот вопрос нам известен: нужно сосредоточиться на поведении каждой абстракции, основывающемся на анализе вариантов использования каждой сущности, и только затем принять решение о размещении поведения. После того, как мы проделаем такую работу в отношении нескольких основных объектов, станут ясны общие механизмы, понимание которых поможет нам правильно разместить оставшиеся абстракции.
Для примера рассмотрим поведение классов Order и ProductRecord. Анализ первого из них дает нам следующий перечень необходимых операций:
-
construct
-
setCustomer
-
setOrderAgent
-
addItem
-
removeItem
-
orderID
-
customer
-
orderAgent
-
numberOfItems
-
itemAt
-
quantityOf
-
totalValue
Перечисленные сервисные операции можно сразу выразить на языке C++, предварительно дав два новых определения типов:
// типы идентификационных номеров
typedef unsigned int OrderID;
// тип, описывающий местную валюту
typedef float Money;
Теперь получаем следующее определение класса:
class Order {
public:
Order();
Order(OrderID);
Order(const Order&);
~Order();
Orders operator=(const Orders);
int operator==(const Orders) const;
int operator!=(const Orders) const;
void setCustomer(Customer&);
void setOrderAgent(OrderAgent&);
void addItem(Product&, unsigned int quantity = 1);
void removeItem(unsigned int index, unsigned int quantity = 1);
OrderID orderID() const;
Customer& customer() const;
OrderAgent& orderAgent() const;
unsigned int numberOfItem() const;
Product& itemAt (unsigned int) const;
unsigned int quantityOf(unsigned int) const;
Money totalValue() const;
protected:
...
};
Обратим внимание на наличие нескольких вариантов конструктора. Первый из них используется по умолчанию (Order()) для создания объекта с новым уникальным значением идентификатора OrderID.