Программирование по контракту — различия между версиями
(→Пример) |
(→Пример) |
||
| Строка 72: | Строка 72: | ||
| − | <tex> void </tex> setHours(int newHours) | + | <tex> void </tex> <tex>setHours(int newHours)</tex> |
| − | <tex> pre: </tex> 0 <= newHours <= 23 | + | <tex> pre: </tex> <tex>0 <= newHours <= 23</tex> |
| − | <tex> post: </tex> hours == newHours | + | <tex> post: </tex> <tex>hours == newHours</tex> |
| − | <tex> void </tex> setMinutes(int newMinutes) | + | <tex> void </tex> <tex>setMinutes(int newMinutes)</tex> |
| − | <tex> pre: </tex> 0 <= newMinutes < 60 | + | <tex> pre: </tex> <tex>0 <= newMinutes < 60</tex> |
| − | <tex> post: </tex> minutes == newMinutes | + | <tex> post: </tex> <tex>minutes == newMinutes </tex> |
| − | <tex> void </tex> setSeconds(int newSeconds) | + | <tex> void </tex> <tex>setSeconds(int newSeconds)</tex> |
| − | <tex> pre: </tex> 0 <= newSeconds < 60 | + | <tex> pre: </tex> <tex>0 <= newSeconds < 60</tex> |
| − | <tex> post: </tex> seconds == newSeconds | + | <tex> post: </tex> <tex>seconds == newSeconds</tex> |
Постусловие: (например для getHours()) возвращенное значение будет являться текущим часом. | Постусловие: (например для getHours()) возвращенное значение будет являться текущим часом. | ||
Версия 18:45, 30 сентября 2013
Программирование по контракту обеспечивает проверку предусловий и постусловий при выполнении методов классов, пользовательских функций. Также немаловажную роль в правильности написания функций играют инварианты.
Предусловие
| Определение: |
| Предусловие - должно быть выполнено до исполнения действия. |
Постусловие
| Определение: |
| Постусловие - должно быть выполнено после исполнения действия. |
Инвариант
| Определение: |
| Инвариант - определяет глобальные свойства некоторого класса, которые должны соблюдаться после его создания на протяжении всего времени жизни. |
Пример
Необходимо гарантировать, что функции данного класса будут возвращать корректные данные, либо, вообще не будут работать.
class Time {
int hours;
int minutes;
int seconds;
int getHours();
{
return hours;
}
int getMinutes();
{
return minutes;
}
int getSeconds()
{
return seconds;
}
void setHours(int newHOURS);
{
hours = newHOURS;
}
void setMinutes(int newMINUTES);
{
minutes = newMINUTES;
}
void setSeconds(int newSECONDS)
{
seconds = newSECONDS;
}
}
Инвариант:
Постусловия и предусловия:
возвращенное значение будет являться текущим часом.
возвращенное значение будет являться текущей минутой.
возвращенное значение будет являться текущей секундой.
Постусловие: (например для getHours()) возвращенное значение будет являться текущим часом.
Решение 1
Выбрасывать исключение. Имеет недостатки: неочевидность проверки, необходимость писать кучу кода вручную.
void getHours(newHours){
if (newHours < 0 || newHours > 23)
throw GREAT_Time_Exception;
return hours;
}
Решение 2
Java поддерживает механизм аннотаций (рекомендаций компилятору, препроцессору) – метаданные, которые могут быть добавлены в исходный код программы, не влияя на него семантически, т.е. не меняя его поведение. При этом, они могут использоваться на этапе анализа кода, компиляции и выполнения.
@Contracted // говорит о том, что класс использует контракты – для отображения в IDE
class Time
{
@Ensures ({“result >= 0”,“result <= 23” })
int getHours();
{
return HOURS;
}
@Requires ({“newHOURS>= 0”,“newHOURS<= 23” })
@Ensures (“HOURS == newHOURS”)
}
@Requires – буквально означает, «Убедиться, что ДО выполнения подпрограммы («условие выполняется»)» Иначе – бросить исключение.
@Ensures – буквально означает, «Убедиться, что ПОСЛЕ выполнения подпрограммы ( «условие выполняется»)»
Здесь мы видим, что, как и в Решение 1, осуществляется проверка пред и пост условий для наших методов. В чем разница? Разница в том, что во втором случае это более наглядно и удобно.
Пример
Рассмотрим стек на массиве. У него есть переменные
число элементов
массив элементов
Методы:
добавить элемент
удалить элемент
получить элемент на вершине
число элементов
проверка на пустоту
Инвариант:
Размер не отрицателен,
Элементы заполнены
Контракты: