среда, 11 мая 2011 г.

с. 167


"Схематическое представление проекта с помощью диаграммы классов и диаграммы взаимодействия помогает привести мысли в порядок и существенно облегчает процесс кодирования."
-----

среда, 27 апреля 2011 г.

c. 166 Связывание Измерения и Показателя


Что ж, получилось нечто похожее, как и у меня... Но так явно включать Показатель в Измерение... Мне не нравится. В моём коде эта функциональность выглядит так:
Quantity.
this.rangeName = resolutionType.getResolutionRangeName(value);
То есть Количество, которое является результатом некоторого измерения, само определяет, к какому численному диапазону оно относится. Класс Измерение никак не вмешивается в этот процесс.
-----
"Нет необходимости чересчур формально подходить к выполнению проекта и пытаться использовать абсолютно все возможности языка UML. Вполне достаточно пользоваться только теми из них, которые представляются вам полезными."
"Если ... я сочту, что диаграмма ... не вносит никакой дополнительной ясности в программный код, то сдам её в архив."
-----

вторник, 19 апреля 2011 г.

с. 165 Модификация модели спецификации (Фаулер)


Итак... Для Типа Показателя смоделирована квалифицированная роль Строка. Что это такое?.. Показатель связан с Типом Показателя посредством роли Строка. В каждом экземпляре Показателя Тип Показателя представлен Строкой?.. В Показателе Строка, т.е. Тип Показателя, может присутствовать, а может и отсутствовать. А зачем нужен Показатель без Типа Показателя?.. Что он показывает, такой Показатель?.. Смотрим в другом направлении. Строка (Тип Показателя) ассоциирована с Показателем (максимум с одним), либо не ассоциирована... Строка Типа Показателя связана с максимум одним Показателем... Непонятно. Вот тот же пример взять. Есть два Показателя: "мужчина" и "женщина". Оба они ассоциируются с Типом показателя "род". Что в этом случае есть Строка?.. Строка01 связана с "мужчина", Строка02 связана с "женщина". Получается, что Строка - это интегрированный в Тип Показателя Показатель... Ну вот, начало потихоньку проясняться... И всё равно как-то плохо смотрится, что Показатель может быть сам по себе, без Типа Показателя. И именно поэтому Наблюдение имеет отдельную ассоциацию с Типом Показателя. Кстати, класс Observation, созданный по мотивам Наблюдения, не имеет выделенной связи с Типом Показателя, только через Показатель...
Прямую связь с Типом Показателя имеет Измерение, которое наследует Наблюдение. А на диаграмме это не отмечено. 
Интересно, а если Наблюдение будет иметь связь с Показателем, который имеет связь с Типом Показателя, то нужно будет вводить проверку, чтобы Наблюдение не было связано с другим экземпляром Типа Показателя? Запутанно как...
Удаление класса Измерение требует изменения класса Наблюдение. И в нём добавляется куча контролей, например, с тем же нулевым количеством. Каким же в итоге получится интерфейс этого класса и сколько трудов понадобится для его внутренней реализации? Не нравится мне это.


пятница, 1 апреля 2011 г.

с.164

Новый класс Quantity. Опять самому придумывать?..
-----
Measurement. Метод public String toString().
Переменная _amounts - это на самом деле _amount ?
Экземпляр класса PhenomenonType используется в методе toString(), однако это класс не имеет аналогичного метода, значит выводиться будет чёрт знает что.
-----
Observation. Метод protected void initialize(Patient patient, Date whenObserved).
Это тот же самый конструктор, но без Показателя. Measurement не может использовать настоящий конструктор своего родителя. Как-то это странно выглядит, однако.
-----
NullQuantity - из серии "тоже сам выдумывай"...
И Observation.isMeasurement() тоже.
И Measurement.amount() ...
Я понимаю, что в книге необязательно размещать весь код, но как-то всё равно неприятно.
-----
"Роль от Типа Показателя к Показателю моделируется как некая квалифицированная роль, поскольку это главный интерфейс класса Тип Показателя. Аналогично показана связь Наблюдения с Типом Показателя, поскольку и здесь существует интерфейс, хотя имеется только одно измерение с прямым указателем на Показатель."
Честно говоря, полная белиберда для меня... Не могу отсюда выудить ни одного полезного момента. Попробую подумать очень хорошенько...

вторник, 29 марта 2011 г.

c. 163 Поиск последнего наблюдения показателя


Неужели у меня тоже получится так сложно?..
-----
Patient
public Phenomenon phenomenonOf (PhenomenonType phenomenonType)
По названию метода никак не понятно, что он возвращает последний показатель указанного типа.
---
public Phenomenon phenomenonOf (PhenomenonType phenomenonType).
return ( latestObservation(phenomenonType) == null ? new NullPhenomenon() : latestObservation(phenomenonType).phenomenon() );
Неясно, что такое NullPhenomenon. Как именно этот объект будет использоваться? Почему не возвращается простой null? Это нужно знать, чтобы правильно его написать.
По идее, NullPhenomenon должен наследовать Phenomenon, однако для Phenomenon не определён конструктор Phenomenon(). Соответственно, нет такого конструктора и у NullPhenomenon. И как это должно заработать?

public class NullPhenomenon extends Phenomenon {
    public NullPhenomenon() {
        super (name, type); // Какие значения я должен сюда положить? Особенно интересует type, который не может быть null.
    }
}
-
Два раза вычисляется latestObservation(phenomenonType).
Observation. Метод phenomenon() нужно дописать самому.
---
private Enumeration observationsOf (PhenomenonType value).
Enumeration e = observations();
Метод observations() тоже нужно писать самому. И если это просто _observations.elements(), то зачем отдельный метод?
---
Observation. Метод whenObserved() тоже не описан. Выдавать просто дату?
---
После "парного программирования" с Лёнькой получился такой код:
public Observation getLatestObservation (ResolutionType resolutionType) {
 List resolutionTypeObservations = this.getObservations (resolutionType);
 return resolutionTypeObservations.isEmpty () ? new NullObservation (resolutionType) : Collections.max (resolutionTypeObservations); 
    }
    
      private List getObservations (ResolutionType resolutionType) {
 List resolutionTypeObservations = new ArrayList();
 for (Observation observation : this.history) {
     if (observation.getResolutionTypeName().equals(resolutionType.getName())) {
  resolutionTypeObservations.add(observation);
     }
 }
 return resolutionTypeObservations;
    }

понедельник, 28 марта 2011 г.

с. 162 Создание наблюдения


Для того, чтобы заработал это код, пришлось написать несколько методов. Надеюсь, их интерфейс я понял и реализовал правильно. Посмотрим, что будет дальше.
А мой код для создания наблюдения получился таким:
ResolutionType sex = new ResolutionType("gender");
 String[] sexes = {"male", "female"};
 sex.addNewResolutionValues (sexes);
 Patient patient = new Patient("Adams");
 Calendar dateAndTime = Calendar.getInstance();
 dateAndTime.set(96, 3, 1);
 Observation observation = 
  new Resolution (sex.getResolutionValue ("male"), dateAndTime);
 patient.addObservation(observation);

Страничка закончилась. Код пока не работает. С интересом перехожу на следующую...

понедельник, 14 марта 2011 г.

с. 161 Создание типа показателя "gender"


Так как класс QuantityRange до сих пор не создан, выполнение кода завершается с ошибкой "Unresolved compilation problem: QuantityRange cannot be resolved to a type". Для того, чтобы всё-таки проверить код, создаю пустышку.
Кроме этого, создал класс BigStore, который реализует интерфейс с persist() и get(). Потом посмотрим, правильно ли я интерпретировал текст.
-----
Как лихо Фаулер завернул, однако. Создал тип показателя "пол", для которого не предусмотрена количественная характеристика. А ведь на с.154 сам ввёл в рассмотрение класс Количественный Диапазон, что и отражено в диаграмме на с. 156. А сейчас у него получились показатели без диапазонов. Интересно, как он будет создавать показатели с диапазонами, если у него никак пока не прописано их использование.
И что же мне делать? Для типа показателя "пол" нужно создавать особый как бы диапазон, в котором будет только имя и никаких границ. Но какой тогда это диапазон? Просто какой-то подтип типа показателя: "пол.мужской", "пол.женский"... А какую единицу измерения использовать? Выходит, тип показателя может быть без единицы измерения. Но тогда такой тип показателя нельзя использовать в веточке для измерений. И что же? Две группы типов показателей формировать из-за этого, вводить дополнительные условия? Нут уж, некрасиво это.
-----
В связи со всем этим, пришлось переделать диаграмму. И получилось вот что...


А теперь непосредственно код.

"интерфейс" Наблюдение

package main.alexded;

import java.util.Calendar;

public interface Observation {

/** Результат наблюдения */
String getResult();

/** Название типа показателя */
String getResolutionTypeName();

/** Момент времени наблюдения */
Calendar getDateAndTime();

}


Показатель package main.alexded; import java.util.Calendar; /** Показатель */ public class Resolution implements Observation { @SuppressWarnings("unused") private Resolution() { } public Resolution ( ResolutionValue inputValue, Calendar inputDateAndTime) { this.value = inputValue; this.dateAndTime = inputDateAndTime; } public Calendar getDateAndTime() { return this.dateAndTime; } public String getResolutionTypeName() { return this.value.getResolutionTypeName(); } public String getResult () { return this.value.getResolutionName(); } private ResolutionValue value; /** Момент времени наблюдения */ private Calendar dateAndTime; }
Значение package main.alexded; public class ResolutionValue { private ResolutionType resolutionType; private String name; /** Значение показателя */ public ResolutionValue ( String inputName, ResolutionType inputResolutionType) { this.name = inputName; this.resolutionType = inputResolutionType; this.resolutionType.addResolutionValue(this); } /** Блокировка конструктора */ @SuppressWarnings("unused") private ResolutionValue () {} /** Название показателя */ public String getResolutionName () { return this.name; } public String getResolutionTypeName() { return this.resolutionType.getName(); } }
Тип показателя package main.alexded; import java.util.ArrayList; /** Неколичественный тип показателя */ public class ResolutionType { /** Название типа показателя */ private String name; /** Диапазоны показателей */ private ArrayList resolutionValues = new ArrayList(); @SuppressWarnings("unused") private ResolutionType() {} public ResolutionType(String inputName) { this.name = inputName; } public void addResolutionValue (ResolutionValue inputResolutionValue) { this.resolutionValues.add (inputResolutionValue); } public void addNewResolutionValue (String resolutionValueName) { new ResolutionValue (resolutionValueName, this); } public void addNewResolutionValues (String[] resolutionValuesNames) { for (int i = 0; i < resolutionValuesNames.length; i++) { this.addNewResolutionValue(resolutionValuesNames[i]); } } public String getName() { return this.name; } }
Диапазон package main.alexded; /** Диапазон показателя */ public class ResolutionRange extends ResolutionValue { /** Верхняя граница диапазона */ private int maxValue; /** Нижняя граница диапазона */ private int minValue; public ResolutionRange ( String inputName, int inputMinValue, int inputMaxValue, QuantitativeResolutionType inputResolutionType) { super(inputName, inputResolutionType); this.minValue = inputMinValue; this.maxValue = inputMaxValue; } }
Количественный тип показателя package main.alexded; /** Количественный тип показателя */ public class QuantitativeResolutionType extends ResolutionType { private Unit unit; public QuantitativeResolutionType (String typeName, Unit typeUnit ) { super(typeName); this.unit = typeUnit; } public String getResolutionRangeName (Integer resolutionResult) { return null; } public void addResolutionRange (ResolutionRange inputResolutionRange) { if (validateResolutionRange (inputResolutionRange)) { super.addResolutionValue(inputResolutionRange); } else { throw new IllegalArgumentException("Not valid Resolution Range"); } } private boolean validateResolutionRange(ResolutionRange inputResolutionRange) { /* TODO : Проверить, может ли вписаться данный диапазон в коллекцию уже существующих. Можно, конечно, предстваить себе ситуацию, когда один диапазон охватывае несколько других, но такие обощения пока оставим на потом */ return true; } }

среда, 9 марта 2011 г.

c. 160 Классы Тип Показателя и Показатель



Что означает такой конструктор?

public PhenomenonType (String name) {
 super (name);
}


Какой на самом деле объект создаётся? Какого типа? Родительского? Не верится что-то... Просто выполняется метод-конструктор родительского класса для того, чтобы задействовать методы родительского класса? Чтобы не обращаться к ним по-отдельности? Наверное, так. Как-то не очень хорошо я чувствую этот механизм.
-----
Метод setPhenomena (String[] names). В этом методе никак не учитываются диапазоны. Получится просто коллекция Показателей с названиями и указанием, к какому типу они относятся. Но как же сделать между ними количественное различие?
-----
public Enumeration phenomena(). Если Enumeration - это интерфейс, то какой объект, реализующий этот интерфейс, возвращает этот метод?
Лёнька подсказал, как это понимать. Реализующий интерфейс объект, конечно, есть, но он спрятан в коде, не моём коде, а где-то в каком-то пакете. А нам просто не нужно его знать, достаточно просто пользоваться предоставляемыми им методами.
-----
Это для меня новое - использовать this в конструкторе. Казалось бы, конструктор конструирует объект, то есть объект ещё не готов, а тут на тебе - this! Получается, что выдаётся ссылка на объект, который ещё не готов в этот момент. Не знал, что так можно. И вообще, интересный способ организации связи.
-----
Итак, при создании Показателя он сразу же ассоциируется с Типом Показателя. А вот обратного не наблюдается. Тип Показателя вполне может быть создан без связи с Показателями.
-----
Загадочное свойство типа QuantityRange. Пока нигде не задействовано. И потому Eclipse на него ругается...
-----
Ещё непонятно, зачем в DomainObject пустой конструктор прописан. С какой целью? Имеет ли это какое-то отношение к наследникам?
-----
Vector используется не параметризированный. Eclipse тоже на это ругается. Вероятно, это связано с разными версиями Java. И Enumeration хочет быть параметризированным. Кстати, всегда ли это возможно. Ведь Vector не должен содержать элементы только одного типа...
-----
А теперь буду писать свои классы, по своей диаграмме. Интересно, какие вопросы при этом возникнут.

среда, 2 марта 2011 г.

c. 159 Переход к кодированию



"Некоторые разработчики испытывают трудности при работе с двунаправленными связями. Я не думаю, что могут возникнуть какие-либо проблемы, если обеспечить такую реализацию, при которой один класс несёт полную ответственность за поддержание данной связи в актуальном состоянии."
Что это означает?.. "... один класс несёт полную ответственность". Один из двух или каждый из двух? Взять, к примеру, мои Тип Показателя и Диапазон. Как поддерживать между ними двунаправленную связь? При создании нового Диапазона нужно сразу же внести его в список диапазонов соответствующего Типа Показателя? А если создаётся новый Тип Показателя, сразу же создавать совокупность Диапазонов?
А у Фаулера, соответственно, при создании Показателя нужно тут же рассказать о нём Типу Показателя, а при создании Типа Показателя нужно сразу же создать набор Показателей этого типа.
Так, что ли? Интересно будет посмотреть реализацию.

вторник, 1 марта 2011 г.

с. 158 Тип Показателя знает все свои Диапазоны

... новое Измерение должно установить, существует ли Показатель, который может быть для него назначен."
Это логично, что для Измерения можно подобрать соответствующий Показатель. Но то, что его может не быть, уже не так хорошо выглядит... Но так может быть, да...
На моей диаграмме выяснение такого соответствия опущено на один уровень вглубь. Для Количества может быть определён Диапазон. Но, опять же, какой класс занимается этим? И мне бы не хотелось, чтобы для какого-то Количества не было Диапазона.
"... Измерение может запросить ассоциированный с ним Тип Показателя, имеется ли соответствующий Показатель".
То есть подразумевается, что Тип Показателя знает все свои Показатели. В моём случае, Тип Показателя должен знать все свои Диапазоны.


В случае Измерения теперь результат может быть таким: "6 футов (средний рост)". 

среда, 23 февраля 2011 г.

с. 157 Момент последнего наблюдения


"... последние данные о сердечном ритме пациента".
Неважно, какие это будут данные - точное значение измерения или его обощенный результат. Важно только время. Нужны самые свежие данные.
"Найти последнюю Категорию Наблюдения..."
Странно, этого понятия на диаграмме уже нет...
Предлагаются следующие методы:

последнееЗначение(ТипПоказателя):Количество;
показатель(ТипПоказателя):Показатель.

То есть интересует не просто последнее наблюдение, а последнее классифицированное наблюдение. А какой в этом смысл? Допустим, последнее наблюдение для типа показателя "Сердечный ритм" было измерением, и оказалось, что результат равен "90 ударов в минуту", а вот предпоследнее наблюдение было определением показателя и результат был "высокий". И что нам выдадут методы? Несоответствующие друг другу результаты. Ладно, может быть, я не так понял. Но зачем два метода? Почему нельзя обойтись простым последнееНаблюдение(ТипПоказателя) ? Этот метод выдаст результат в зависимости от реального реализатора интерфейса Наблюдение: если это было Измерение, то будет "90 ударов в минуту", если Показатель, то "высокий".
Из конкретного измерения можно, в принципе, определить диапазон и, соответственно, Показатель. В обратную сторону такое не сработает. Но кто будет заниматься этим сопоставлением? Это тот самый кто-то, занимающийся обобщением для Показателя, но которого нет на диаграмме. Если он на ней появится, то в Измерении можно будет создать метод, запрашивающий диапазон, соответствубщий результату.


Ещё один момент... Наблюдение на диаграмме Фаулера связано с Показателем. Однако Показателя для некоторого Наблюдения может и не быть (0...1). Тогда что это за наблюдение? Ни Показателя, ни Измерения. Смысл такого объекта Наблюдение?..

вторник, 22 февраля 2011 г.

с. 156 Диаграмма уровня спецификации

Интересненько... Наблюдение всё-таки осталось. И это не интерфейс, а класс. Оно и было классом с самого начала. А у меня Наблюдение - это интерфейс.
А зачем Фаулеру вообще Наблюдение? В Наблюдении может быть Показатель, а может и не быть. А так как Измерение - наследник Наблюдения, то и в Измерении может быть Показатель. Вернее, Показатель ассоциирован с Измерением. Не знаю как кому, а мне такой вариант не нравится.
А как насчёт инкапсуляции? Каким образом в Пациенте реализовать доступ к значению Измерения? Ведь в Наблюдении таких данных нет. По идее, сделать в Пациенте можно только так:
(Измерение)Наблюдение.значение()
А просто для Наблюдения сделать пустой метод? В общем, по-любому в Измерении подобный метод должен переопределяться. И откуда вообще Пациент должен узнать, что он может использовать такой метод - значение() ?

суббота, 12 февраля 2011 г.

с. 155 Оптимизация диаграммы

"В языке Java, как и в большинстве других языков программирования, можно определить только одну классификацию".
Что-то мне это непонятно. Что имеется ввиду? Что невозможно предложить такой интерфейс Наблюдение, который смогли бы реализовать и Измерение, и Категория Наблюдения? В принципе, на моей диаграмме одно несоответствие есть: в Измерении "результат" - это Количество, а в Категории Наблюдения - Показатель. Свойство "тип показателя" в Категории Наблюдения можно взять из Показателя, но это будет уже дублирование... Тогда можно сделать это не свойством, а методом "получить Тип Показателя()". А вот срезультатом нужно что-то придумывать.
"Я решил эту проблему, допустив, что любое Наблюдение должно иметь ассоциированный с ним Показатель, который позволяет классу Наблюдение эффективно реализовывать как понятие Наблюдение,  так и понятие Категория Наблюдения".
Какая-то здесь путаница, однако. Это что же, мне нужно каким-то макаром ассоциировать с Показателем Измерение? Но ведь Показатель ассоциирован с Диапазоном, который есть диапазон всё-таки, а у меня в Измерении указывается точное значение измерения в виде Количества. Подменять Количество Диапазоном плохо пахнет, как говорится. Кроме того, "... позволяет классу Наблюдение реализовывать..." Наблюдение - это интерфейс, а не класс, и потому он ничего реализовывать не может. Может быть, имеется ввиду класс Измерение, который должен теперь реализовывать понятия Наблюдение и Категория Наблюдения? Интерфейс долой? И как же мне нужно изменить свою диаграмму?
Ну что ж, пока диаграмма стала такой:

Однако это ещё не конец. Категорию Наблюдения нужно вообще убрать, Показателя будет вполне достаточно. А ещё было бы неплохо ассоциировать Тип Показателя с Единицей, чтобы невозможно было измерить "рост", к примеру, в "килограммах"...

Пришла в голову интересная идея...
Показатель определяется Диапазоном, однако для того, чтобы выбрать Диапазон, нужно ведь произвести какое-то измерение. То есть сначала что-то измеряем, находим значение, а затем смотрим, к какому диапазону это значение относится. Таким образом, любой Диапазон можно сопроводить Измерением, а любое Измерение можно сопоставить с некоторым Диапазоном. Что и этого следует?
Вариант первый. Ассоциировать Диапазон с Измерением. В этом случае любое Наблюдение будет Показателем. Однако любой показатель должен сопровождаться Измерением.
Вариант второй. Ассоциировать Измерение с Диапазоном. То есть каждое Измерение можно сопоставить с некоторым Диапазоном. В этом случае Показатель не должен иметь ввиду какое-то Измерение. Зато для каждого Измерения нужно искать свой Диапазон. И в чём тогда будет различие между Измерением и Показателем? Тем, что Измерение будет расширенным вариантом показателя, за счёт обладания точным значением измерения.
В любом случае, можно выделить такие классы: с измерением, с диапазоном и с обоими понятиями вместе. Последний класс расширяет первые два. Какую цепочку наследования выбрать?
Что на самом деле является расширением? Измерение расширяет диапазон или диапазон расширяет измерение? Что первично, а что вторично? Что уточняет другое? 38 градусов - это какая температура? А высокая температура - это сколько градусов?
Не хочется мне что-то уже ничего менять. Пускай остаётся так, как есть. Посмотрим, что из этого получится.

среда, 9 февраля 2011 г.

c. 154 Диаграмма объектов наблюдения

При построении диаграммы объектов (диаграммы экземпляров) возникли трудности с определением Диапазона для Типа Показателя "Группа крови". Для группы крови нельзя указать верхнюю и нижнюю границу, она просто "Первая", к примеру. В общем, получилось, что Диапазон может применяться только для исчисляемых величин, которые имеют единицы измерения и значение, определяемое в этих единицах. Для неисчисляемых величин нужно ввести новое понятие вместо Диапазона. Или просто пока принять, что обязательным полем для Диапазона является только "название". Может быть, в дальнейшем такая детализация и не понадобится. У Фаулера, по крайней мере, её нет.
А вот Фаулер и сам говорит про Диапазон. Его идея относительно Количественного Диапазона может быть решением проблемы, так как подразумевает возможность создания других типов диапазонов, реализующих общий интерфейс Диапазон.

вторник, 8 февраля 2011 г.

с. 153 Сравнение диаграмм

Интересно сравнить диаграммы...
Везде, где у меня проставлено " 0...* ", в книге написано просто " * ". Наверное, " * " означает все числа, включая ноль.
Количество, Единица измерения и Диапазон представлены отдельно... Этим что, как бы подразумевается их участие в общем деле, но не указывается, как именно? А Диапазон, кстати, такой, какой был до Лёнькиного замечания, с Количествами. :)
Показатель - без свойства Тип Показателя. Сама наявность ассоциации указывает на то, что Показатель знает про Тип Показателя? А может ли Показатель обойтись без этого свойства? В ассоциации у Фаулера кратность Типа Показателя может быть нулевой. Это как же - Показатель без Типа Показателя? А вот для Измерения кратность Типа Показателя равна единице. Как-то это не очень понятно. Что-то меряем, но не знаем что? Пользуемся названием соответствующего экземпляра Диапазона?
Из увиденного не нашёл повод что-либо изменять в своей диаграмме. Посмотрим на дальнейшее развитие событий.

среда, 2 февраля 2011 г.

с. 152 Диаграмма понятий предметной области

Начинается всё с концептуальной модели, работаем с понятиями предметной области и вообще ещё не думаем о программировании.
"Единицы просто представляют собой те категории измерения, которые нужны нам для работы". Категории измерения... Мне пока непонятно, что имеется ввиду под этим термином.
Что ж, на основании написанного у меня получилась вот такая диаграмма:




вторник, 1 февраля 2011 г.



По моему мнению, вариант использования "просмотр и ввод данных наблюдения пациентов" - на самом деле два варианта использования: "просмотреть данные" и "ввести данные". Каждое из этих действий направлено на достижение конкретной цели основным действующим лицом, и цели эти - разные.