пятница, 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 футов (средний рост)".