Как инвариант класса может усилить предварительные и постусловия?

Ссылка

Вы можете рассматривать инвариант класса как критерий работоспособности, который должен выполняться всеми объектами между операциями. Таким образом, в качестве предварительного условия каждой открытой операции класса можно предположить, что инвариант класса выполняется. Кроме того, это может считаться постусловием каждой публичной операции, которое выполняется инвариантом класса. В этом смысле инвариант класса служит общим усилением как предусловия, так и постусловия публичных операций в классе. Эффективное предусловие - это сформулированное предусловие в сочетании с инвариантом класса. Точно так же эффективное постусловие - это сформулированное постусловие в сочетании с инвариантом класса.

public class Server
{
     // other code ommited
    public Output Foo(Input cmdIn)
    {
        ...
        return cmdOut;
    }
}


public class Caller
{  
    // other code ommited

    /* calls Server.Foo */
    public void Call()
    {...}
}

public class Input
{
    // other code ommited

    public int Length
    {...}
}

public class Output
{
    // other code ommited

    public int Length
    {...}
}

1. Если инвариант класса определен для Server класса:

a) Предварительные условия обычно формулируются в терминах формальных параметров вызываемой операции, так как же инвариант класса усилить предварительные условия метода (Foo's)?

б) Постусловие сформулировано в терминах возвращаемого значения вызываемого метода, поэтому как инвариант класса может усилить постусловия метода (Foo) ?

2. Может ли инвариант класса, определенный для Caller class, каким-либо образом усилить предварительные условия или постусловия Foo?

3. Если инвариант класса определен в параметре Foo cmdIn:

a) Если предварительное условие в Foo указывает, что cmdIn.Length находится в пределах диапазона 1-20, но один из инвариантов класса, определенных в Input, утверждает, что Input.Length должен находиться в пределах диапазона 2-19, тогда Foo предварительное условие действительно было усилено?

б) Разве логика в a) не ошибочна, поскольку, если инвариант класса уже заявляет, что Input.Length должен находиться в диапазоне 2-19, не является ли это ошибкой для Foo для определения предусловия, которое не всегда true (cmdIn.Length не может содержать значения 1 или 20)

c) Но если инвариант класса, определенный в Input, указывает, что Input.Length должен находиться в диапазоне 0-100, тогда предусловие Foo не усиливается?

d) Могут ли инварианты классов, определенные в cmdIn, также каким-то образом усилить постусловие Foo?

4. Если инвариант класса определен в возвращаемом значении Foo

a) Если постусловие на Foo указывает, что cmdOut.Length находится в пределах диапазона 1-20, но один из инвариантов класса, определенных в Output, утверждает, что Output.Length должен находиться в пределах диапазона 2-19, тогда Foo постусловие действительно было усилено?

б) Но если инвариант, определенный в Output, утверждает, что Output.Length должен находиться в диапазоне 0-100, тогда постусловие Foo не усиливается?

c) Могут ли инварианты классов, определенные на Output, также каким-то образом усилить предусловие Foo?

5. Но у меня сложилось впечатление, что процитированная статья означает, что просто имея инвариант класса (и даже если этот инвариант не каким-либо образом оперировать (прямо или косвенно) с параметрами и / или возвращаемым значением Foo, это все равно усилит предварительные условия и постусловие Foo? Если это действительно подразумевается в статье, как это возможно?

Благодарность




Ответы (1)


a) Предварительные условия обычно формулируются в терминах формальных параметров вызываемой операции, так как же инвариант класса может усилить предусловия метода (Foo)?

Я подозреваю, что это ключ к вашему недоразумению. Предварительные условия могут включать формальные параметры, но не ограничиваются ими. Они могут - и часто делают - также относиться к функциям класса (атрибутам / операциям). В общем, комбинация инвариантов и предварительного условия определяет набор ограничений, которые должны быть удовлетворены, прежде чем операция будет обязана соответствовать своему постусловию при вызове. Точно так же операция должна гарантировать, что и ее пост-условие, и любые инварианты будут выполнены после ее завершения. Возьмем пример ограниченного буфера:

Class BoundedBuffer<T> {
   public int max    // max #items the buffer can hold
   public int count  // how many items currently in the buffer

   void push(T item) {...}
   T    pop() {...}
}

Предварительным условием для push() будет то, что буфер не достиг своего максимального размера:

 pre: count < max

Итак, здесь предварительное условие даже не упоминает формальный параметр операции. Мы также можем указать инвариант для буфера:

inv: count >=0  //can't have -ve number of elements in the buffer

Он усиливает предварительное условие, поскольку включает в себя то, что должно быть истинным до того, как операция push() будет обязана удовлетворять своему пост-условию. Эти два предложения объединены логическим И вместе. Таким образом, эффективное предварительное условие - count >=0 AND count < max. Это более сильное (более ограничивающее) ограничение, чем одно предварительное условие.

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

pre: count < max AND item.size() <= MAX_ITEM_SIZE

Добавление инварианта по-прежнему усиливает эффективное предварительное условие:

pre: count < max AND item.size() <= MAX_ITEM_SIZE AND count >=0

Итак, вкратце: инварианты должны сохраняться до вызова операции и после ее завершения. Следовательно, они усиливают оба.

  1. Может ли инвариант класса, определенный в классе Caller, каким-либо образом усилить предусловия или постусловия Foo?

Нет. Инварианты применяются только к тому классу, для которого они определены.

Ответы на оставшиеся вопросы логически вытекают сверху.

hth.

person sfinnie    schedule 02.05.2013
comment
Я думал, что предварительные условия - это публичный контракт между вызывающим и методом. Другими словами, я думал, что любые требования, сформулированные в предварительных условиях, должны выполняться вызывающей стороной в том смысле, что вызывающая сторона имеет возможность манипулировать всеми функциями, указанными в предварительном условии. Но вы говорите, что вызывающий может даже не знать о некоторых функциях, указанных в предварительных условиях (тех, которыми он не может / не должен манипулировать, например, значение частных переменных и т. Д.)? - person EdvRusj; 03.05.2013
comment
Забыл добавить: Нет. Инварианты применяются только к тому классу, для которого они определены. Но нельзя ли сказать, что пример в 3a) усиливает предусловие Foo, поскольку из-за инварианта класса, определенного для типа Input, допустимый диапазон параметра Server.Foo cmdIn.Length составляет 2-19 вместо 1-20? - person EdvRusj; 03.05.2013
comment
@EdvRusj: Предварительные условия касаются не только обязанностей вызывающего абонента. Они также предоставляют предположения, на которые вызываемому лицу разрешено полагаться. - person Kevin; 09.12.2014
comment
очень хороший ответ, мне неясно одно: инварианты должны сохраняться до вызова операции и после ее завершения. Это почему? разве не достаточно проводить только в постусловиях? В конце концов, в предварительных условиях я уверен, что объект находится в допустимом состоянии, учитывая, что я еще ничего с ним не сделал. - person Marco Luzzara; 04.02.2021