Программирование по контракту — различия между версиями
Sergej (обсуждение | вклад) (→Пример) |
Sergej (обсуждение | вклад) (→Пример) |
||
| Строка 93: | Строка 93: | ||
<tex> isEmpty - </tex> проверка на пустоту | <tex> isEmpty - </tex> проверка на пустоту | ||
| − | Инвариант | + | Инвариант: |
Размер не отрицателен, <tex>size >=0</tex> | Размер не отрицателен, <tex>size >=0</tex> | ||
Элементы заполнены <tex>elements[0..size - 1] != NULL </tex> | Элементы заполнены <tex>elements[0..size - 1] != NULL </tex> | ||
| + | |||
| + | Контракты: | ||
| + | <tex> push: | ||
| + | |||
| + | pre: element != null | ||
| + | |||
| + | post: size == size' + 1 && elements[size'] == element | ||
| + | |||
| + | void push(Object element) </tex> | ||
| + | |||
| + | <tex> pop: | ||
| + | |||
| + | pre: size > 0 | ||
| + | |||
| + | post: size == size' - 1 && result == elements[size] | ||
| + | |||
| + | Object pop() </tex> | ||
| + | |||
| + | <tex> peek: | ||
| + | |||
| + | pre: size > 0 | ||
| + | |||
| + | post result == elements[size - 1] | ||
| + | |||
| + | Object peek() </tex> | ||
| + | |||
| + | <tex> size: | ||
| + | |||
| + | post: result == size | ||
| + | |||
| + | int size() | ||
| + | |||
| + | isEmpty: | ||
| + | |||
| + | post: result == size > 0 | ||
| + | |||
| + | boolean isEmpty() </tex> | ||
Версия 12:05, 17 июня 2013
Программирование по контракту обеспечивает проверку предусловий и постусловий при выполнении методов классов, пользовательских функций. Также немаловажную роль в правильности написания функций играют инварианты.
Предусловие
| Определение: |
| Предусловие - должно быть выполнено до исполнения действия. |
Постусловие
| Определение: |
| Постусловие - должно быть выполнено после исполнения действия. |
Инвариант
| Определение: |
| Инвариант - определяет глобальные свойства некоторого класса, которые должны соблюдаться после его создания на протяжении всего времени жизни. |
Пример
Необходимо гарантировать, что данный класс будет возвращать корректные данные, либо, вообще не будет работать.
class Time {
intHOURS;
intMINUTES;
intSECONDS;
getHours();
{
return HOURS;
}
getMinutes();
{
return MINUTES;
}
getSeconds()
{
return SECONDS;
}
setHours(newHOURS);
{
HOURS = newHOURS;
}
setMinutes(newMINUTES);
{
MINUTES = newMINUTES;
}
setSeconds(newSECONDS)
{
SECONDS = newSECONDS;
}
}
Предусловие: (например для getHours) Hours >= 0 && Hours < 24. Постусловие: возвращенное значение будет являться текущим часом.
Решение 1
Выбрасывать исключение. Имеет недостатки: неочевидность проверки, необходимость писать кучу кода вручную.
getHours(){
if (HOURS<0 ||HOURS>23)
throw GREAT_Time_Exception;
return HOURS;
}
Решение 2
Java поддерживает механизм аннотаций (рекомендаций компилятору, препроцессору) – метаданные, которые могут быть добавлены в исходный код программы, не влияя на него семантически, т.е. не меняя его поведение. При этом, они могут использоваться на этапе анализа кода, компиляции и выполнения.
@Contracted // говорит о том, что класс использует контракты – для отображения в IDE
class Time
{
@Ensures ({“result >= 0”,“result <= 23” })
getHours();
{
return HOURS;
}
@Requires ({“newHOURS>= 0”,“newHOURS<= 23” })
@Ensures (“HOURS == newHOURS”)
}
@Requires – буквально означает, «Убедиться, что ДО выполнения подпрограммы («условие выполняется»)» Иначе – бросить исключение.
@Ensures – буквально означает, «Убедиться, что ПОСЛЕ выполнения подпрограммы ( «условие выполняется»)»
Здесь мы видим, что, как и в Решение 1, осуществляется проверка пред и пост условий для наших методов. В чем разница? Разница в том, что во втором случае это более наглядно и удобно.
Пример
Рассмотрим стек на массиве. У него есть переменные
число элементов
массив элементов
Методы:
добавить элемент
удалить элемент
получить элемент на вершине
число элементов
проверка на пустоту
Инвариант:
Размер не отрицателен,
Элементы заполнены
Контракты: