Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Орлов_Технологии разработки программного обеспе...doc
Скачиваний:
106
Добавлен:
07.09.2019
Размер:
4.57 Mб
Скачать

V.ПолучитьВес();

// занести в последнийЗамер вес при послед, посещении

общаяСтоимость += v.получитьСтоиность();

потреблениеБулочек += v.получитьБулочки();

}

double изменение = последнийЗамер - первыйЗамер;

r.устВесНаБулочкуСизменение/потреблениеБулочек);

r.устИзненениеВеса(иэненение);

r.устСтоиностьБулочек(общаяСтоиность):

r.устПотреблениеБулочек(потреблениеБулочек);

}

return r;

}

Данный код из-за множества специальных случаев выглядит неуклюже. Для устранения специальных случаев нужно провести рефакторинг. Поскольку третий специальный случай наиболее универсален, надо убрать первые два случая.

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

Листинг 16.17. Лакомка.java

public Отчет создатьОтчет()

{

Отчет r = new Отчет();

double первыйЗамер = 0;

double последнийЗамер = 0;

double общаяСтоимость = 0;

double потреблениеБулочек = 0;

for (int i= 0; i< егоПосещения.size(); i++)

// проход по всем элементам контейнера посещений

{

ПосещениеКафе v = (ПосещениеКафе) егоПосещения.get(i);

// занести в v i-й элемент из контейнера посещений

if (i = = 0)

{

первыйЗамер = v. ПолучитьВес();

//занести в первыйЗамер вес при 1-м посещении

потреблениеБулочек -= v.получитьБулочки();

}

if (i= = егоПосещения.size()- 1) последнийЗамер =

v. получитьВес();

// занести в последнийЗамер вес при послед. посещении

общаяСтоимость += v.получитьСтоимость();

потреблениеБулочек += v.получитьБулочки();

}

double изменение = последнийЗамер – первыйЗамер;

r.устВесНаБулочку(изменение/потреблениеБулочек);

r.устИзменениеВеса(изменение);

r.устСтоимостьБулочек(общаяСтоимость);

r.устПотреблениеБулочекСпотреблениеБулочек);

return r;

}

Теперь попытаемся сделать функцию короче и понятнее. Переместим фрагменты кода так, чтобы их можно было вынести в отдельные функции.

Листинг 16.18. Лакомка.java

public Отчет создатьОтчет()

{

Отчет г = new Отчет();

double изменение = 0;

double общаяСтоимость = 0;

double потреблениеБулочек =0;

double первыеБулочки = 0; double wpb =0;

if (егоПосещения.size() > 0)

{

ПосещениеКафе первоеПосещение =

(ПосещениеКафе) егоПосещения.get(0);

ПосещениеКафе последнееПосещение = (ПосещениеКафе)

егоПосещения.get(егоПосещения.size() - 1);

double первыйЗамер = первоеПосещение.получитьВес();

double последнийЗамер =

последнееПосещение. ПолучитьВес();

изменение = последнийЗамер – первыйЗамер;

первыеБулочки = первоеПосещение.получитьБулочки();

for (int i = 0; i < егоПосещения.size(); i++)

{

ПосещениеКафе v = (ПосещениеКафе)

егоПосещения.get(i);

общаяСтоимость += v.получитьСтоимость();

потреблениеБулочек += v.получитьБулочки();

}

потреблениеБулочек -= первыеБулочки;

if (потреблениеБулочек > 0)

wpb = изменение / потреблениеБулочек;

}

r.устВесНаБулочку(wpb );

r.устИзменениеВеса(изненение);

r.устСтоимостьБулочек(общаяСтоиность);

r.устПотреблениеБулочек(потреблениеБулочек);

return r;

}

Листинг 16.18 иллюстрирует промежуточный шаг в перемещении фрагментов кода. На пути к нему мы выполнили несколько более мелких шагов. Каждый из этих шагов тестировался. И вот теперь тесты стали завершаться успешно. Облегченно вздохнув, мы увидели, как можно улучшить код. Начнем с разбиения единственного цикла на два цикла.

Листинг 16.19. Лакомка.java

if (егоПосещения.size() > 0)

{

ПосещениеКафе первоеПосещение =

(ПосещениеКафе) егоПосещения.get(0);

ПосещениеКафе последнееПосещение = (ПосещениеКафе)

егоПосещения.get(егоПосещения.size() - 1):

double первыйЗамер = первоеПосещение.получитьВес();

double последнийЗамер = последнееПосещение.получитьВес();

изменение = последнийЗамер – первыйЗамер;

первыеБулочки = первоеПосещение.получитьБулочки();

for (int i =0; i < егоПосещения.size(); i++)

{

ПосещениеКафе v = (ПосещениеКафе) егоПосещения.get(i);

потреблениеБулочек += v.получитьБулочки();

}

for (int i =0; i < егоПосещения.size(); i++)

{

ПосещениеКафе v = (ПосещениеКафе) егоПосещения.get(i);

общаяСтоимость += v.получитьСтоимость();

}

потреблениеБулочек -= первыеБулочки;

if (потреблениеБулочек > 0)

wpb = изменение / потреблениеБулочек;

}

Выполним тестирование. На следующем шаге поместим каждый цикл в отдельный приватный метод.

Листинг 16.20. Лакомка.java

public Отчет создатьОтчет()

{

Отчет г = new Отчет();

double изменение = 0;

double общаяСтоимость = 0;

double потреблениеБулочек = 0;

double первыеБулочки =0;

double wpb = 0;

if (егоПосещения. Size() > О)

{

ПосещениеКафе первоеПосещение =

(ПосещениеКафе) егоПосещения.get(0);

ПосещениеКафе последнееЛосещение = (ПосещениеКафе)

егоПосещения.get(егоПосещения.size() - 1);

double первыйЗамер = первоеПосещение.получитьВес();

double последнийЗамер =

последнееПосещение.получитьВес();

изменение - последнийЗамер – первыйЗамер;

первыеБулочки = первоеПосещение.получитьБулочки();

потреблениеБулочек = вычПотреблениеБулочек();

общаяСтоимость = вычОбщуюСтоимость();

потреблениеБулочек -= первыеБулочки;

if (потреблениеБулочек > 0)

wpb = изменение / потреблениеБулочек;

}

r.устВесНаБулочку(wpb);

r.устИзменениеВеса(изменение);

r.устСтоимостьБулочек(общаяСтоимость);

r.устПотреблениеБулочек(потреблениеБулочек);

return r;

}

private double вычОбщуюСтоимость()

{

double общаяСтоииость = 0;

for (int i = 0; i < егоПосещения.size(); i++);

{

ПосещениеКафе v = (ПосещениеКафе) егоПосещения.get(i);

общаяСтоимость += v.получитьСтоимость();

}

return общаяСтоимость;

}

private double вычПотреблениеБулочек()

{

double потреблениеБулочек = 0;

for (int i - 0; i < егоПосещения.size(); i++)

{

ПосещениеКафе v = (ПосещениеКафе) егоПосещения.get(i);

потреблениеБулочек += v.получитьБулочки();

}

return потреблениеБулочек;

}

После соответствующего тестирования перенесем обработку вариантов потребления булочек в метод вычПотреблениеБулочек.

Листинг 16.21. Лакомка.java

public Отчет создатьОтчет()

{

if (егоПосещения.size() > 0)

{

ПосещениеКафе первоеПосещение =

(ПосещениеКафе) егоПосещения.get(0);

ПосещениеКафе последнееПосещение - (ПосещениеКафе)

егоПосещения.get(егоПосещения.size() - 1);

double первыйЗамер = первоеПосещение.получитьВес();

double последнийЗамер =

последнееПосещение.получитьВес();

изменение = последнийЗамер - первыйЗамер;

потреблениеБулочек = вычПотреблениеБулочек();

общаяСтоимость - вычОбщуюС тонкость ();

if (потреблениеБулочек > 0)

wpb = изменение / потреблениеБулочек;

}

return r;

}

private double вычОбщуюСтоимость()

{

double общаяСтоимость = 0;

for (int i= 0; i < егоПосещения.size(); i++);

{

ПосещениеКафе v = (ПосещениеКафе) егоПосещения.get(i);

общаяСтоимость += v.получитьСтоимость();

}

return общаяСтоимость;

}

private double вычПотреблениеБулочек()

{

double потреблениеБулочек = 0;

if (егоПосещения.size() > 0)

{

for (int i = 1; i < егоПосещения.size(); i++)

{

ПосещениеКафе v = (ПосещениеКафе)

егоПосещения.get(i);

потреблениеБулочек += v.получитьБулочки();

}

}

return потреблениеБулочек;

}

Заметим, что функция вычПотреблениеБулочек теперь суммирует потребление булочек, начиная со второго посещения. И опять выполняем тестирование. На следующем шаге выделим функцию для расчета изменения веса.

Листинг 16.22. Лакомка.java

public Отчет создатьОтчет()

{

Отчет r = new Отчет ();

double изменение = 0;

double общаяСтоимость = 0;

double потреблениеБулочек = 0;

double первыеБулочки = 0;

double wpb = 0;

if (егоПосещения.size() > 0)

{

изменение = вычИзменение();

потреблениеБулочек = вычПотреблениеБулочек();

общаяСтоимость = вычОбщуюСтоимость();

if (потреблениеБулочек > 0)

wpb = изменение / потреблениеБулочек;

}

r.устВесНаБулочку(wpb);

r.устИзменениеВеса(изменение);

r.устСтоимостьБулочек(общаяСтоимость);

r.устПотреблениеБулочек(потреблениеБулочек):

return r;

}

private double вычИзменение()

{

double изменение = 0;

if (егоПосещения.size() > 0)

{

ПосещениеКафе первоеПосещение =

(ПосещениеКафе) егоПосещения.get(0);

ПосещениеКафе последнееПосещение = (ПосещениеКафе)

егоПосещения.get;(егоПосещения.sizе() - 1);

double первыйЗамер = первоеПосещение.получитьВес();

double последнийЗамер =

последнееПосещение. получитьВес();

изменение = последнийЗамер - первыйЗамер;

}

return изменение;

}

После очередного запуска тестов переместим условия в главном методе создатьОтчет и подчистим лишние места.

Листинг 16.23. Лакомка.java

public Отчет создатьОтчет()

{

double изменение = вычИзменение();

double потреблениеБулочек = вычПотреблениеБулочек();

double общаяСтоимость = вычОбщуюСтоимость();

double wpb = 0;

if (потреблениеБулочек > 0)

wpb = изменение / потреблениеБулочек;

Отчет г = new Отчет ();

r.устВесНаБулочку(wpb);

r.устИзменениеВеса(изменение);

r.устСтоимостьБулочек(общаяСтоимость);

r.устПотреблениеБулочек(потреблениеБулочек);

return r;

}

private double вычИзменение()

{

double изменение = 0;

if (eroПосещения.size() > 1)

{

ПосещениеКафе первоеПосещение =

(ПосещениеКафе) егоПосещения.get(0);

ПосещениеКафе последнееПосещение = (ПосещениеКафе)

егоПосещения.get(егоПосещения.size() - 1);

double первыйЗамер = первоеПосещение.получитьВес(0;

double последнийЗамер =

последнееПосещение. получитьВес();

изменение = последнийЗамер – первыйЗамер;

}

return изменение;

}

private double вычОбщуюСтоимость()

{

double общаяСтоимость =0;

for (int i= 0; i < егоПосещения.size(); i++);

{

ПосещениеКафе v = (ПосещениеКафе) егоПосещения.get(i);

общаяСтоимость += v.получитьСтоимость();

}

return общаяСтоимость;

}

private double вычПотреблениеБулочек()

{

double потреблениеБулочек = 0;

if (егоПосещения.size() > 1)

{

for (int i = 1; i < егоПосещения.size(); i++)

{

ПосещениеКафе v = (ПосещениеКафе)

егоПосещения.get(i);

потреблениеБулочек += v.получитьБулочки();

}

}

return потреблениеБулочек;

}

После окончательного прогона тестов констатируем, что цель достигнута — код стал компактным и понятным, обязанности разнесены по отдельным функциям.

Таким образом, в рассмотренном подходе программа считается завершенной не тогда, когда она заработала, а когда она стала максимально простой и ясной.