São pré-condições e pós-condições necessárias, além de invariantes em funções membro se fazer programação por contrato?
-
10-07-2019 - |
Pergunta
Eu entendo que no método DbC, pré-condições e pós-condições estão associadas a uma função.
O que eu estou querendo saber é se isso se aplica a funções membro também.
Por exemplo, supondo que eu usar invariantes no início no final de cada função pública, uma função membro será parecido com este:
edit: (limpado meu exemplo)
void Charcoal::LightOnFire() {
invariant();
in_LightOnFire();
StartBurning();
m_Status = STATUS_BURNING;
m_Color = 0xCCCCCC;
return; // last return in body
out_LightOnFire();
invariant();
}
inline void Charcoal::in_LightOnFire() {
#ifndef _RELEASE_
assert (m_Status == STATUS_UNLIT);
assert (m_OnTheGrill == true);
assert (m_DousedInLighterFluid == true);
#endif
}
inline void Charcoal::out_LightOnFire() {
#ifndef _RELEASE_
assert(m_Status == STATUS_BURNING);
assert(m_Color == 0xCCCCCC);
#endif
}
// class invariant
inline void Charcoal::invariant() {
assert(m_Status == STATUS_UNLIT || m_Status == STATUS_BURNING || m_Status == STATUS_ASHY);
assert(m_Color == 0x000000 || m_Color == 0xCCCCCC || m_Color == 0xEEEEEE);
}
Está tudo bem para usar pré-condições e pós-condições, com apenas funções global / genéricos e usar apenas invariantes dentro das classes?
Este parece ser um exagero, mas talvez o seu o meu exemplo é ruim.
edit:
Não é a pós-condição apenas verificar um subconjunto da invariante?
No exemplo acima, eu estou seguindo as instruções do http://www.digitalmars.com /ctg/contract.html que afirma: "a invariante é verificada quando a completa construtor da classe, no início da destruição de classe, antes de um membro do público é executado e, após um público acabamentos de função".
Graças.
Solução
Sim.
O Classe C invariante é uma propriedade comum de todas as suas instâncias (objetos). Os avalia invariantes para true se e somente se o objeto está em um estado semanticamente válido.
invariante de um elevador pode conter informações como ASSERT(IsStopped() || Door.IsClosed())
, porque é inválido para um elevador para estar em um estado diferente do que parou (digamos, indo para cima) e com a porta aberta.
Em contraste, uma função de membro, tais como MoveTo(int flat)
pode ter CurrentFlat()==flat
como um IsStopped()
como precondição , porque (dependendo do projeto), você não pode invocar a função MoveTo se o elevador é já em movimento. Primeiro, você tem que consultar o seu estado, certifique-se de que ele está parado, e, em seguida, chamar a função.
Claro que pode ser simplificar totalmente como funciona um elevador.
Em qualquer caso, as pré-condições e pós-condições não fará sentido, em geral, as condições invariantes; um elevador não precisa estar no piso 6 a estar em um estado válido.
Um exemplo mais conciso pode ser encontrada aqui: Intercepção e atributos:. Um projeto-por-contrato Amostra por Sasha Goldshtein
Outras dicas
Restringir os contratos nas classes para invariantes não é o ideal.
Pré-condições e Pós-condições não são apenas um subconjunto dos invariantes.
Invariants, pré-condições e pós-condições têm papéis muito diferentes.
Invariants confirma a coerência interna do objeto. Eles devem ser válidos no fim do construtor e antes e depois de cada chamada de método.
Pré-condições são a verificação de que o status do objeto e os argumentos são adequados para a execução do método. Pré-requisitos são complementares aos invariantes. Eles cobrem a verificação dos argumentos (uma verificação mais forte que o próprio tipo, ou seja, não nulo,> 0, .. etc), mas também pode verificar o estado interno do objeto (chamada ou seja, um para file.write ( "Olá ") é uma chamada válida somente se file.is_rw e file.is_open são verdadeiras).
Pós-condições são cheking que o método satisfeito a sua obrigação Pós-condições também são complementares aos invariantes. É claro que o status do objeto tem que ser coerente após a execução do método, mas as pós-condições são a verificação de que a ação esperada foi realizado (ou seja list.add (i) deve ter como consequência que list.has (i) é verdadeiro e list.count = idade list.count + 1).
Bem, a ponto de um invariante é que ele descreve algo que é true do objeto em todos os momentos . Neste caso, há algo na grelha, ou não (nada entre eles). Eles normalmente descrever uma propriedade de todo o estado do objeto.
Pré e pós-condições descrevem coisas que são verdadeiras antes de um executa o método, e logo após, e preocupação vontade apenas o estado que deveria ter sido tocado pelo método . Isso é diferente, presumivelmente, do estado do objeto. Pré e pós-condições pode ser pensado como descrever a pegada de um método -. Exatamente o que ele precisava, apenas o que tocou
Assim, à questão específica, as ideias fazer coisas diferentes, assim você pode muito bem querer tanto. Você certamente não pode apenas usar invariantes em vez de condições pré e pós - neste caso, parte do objeto invariante é "Algo está na grade ou não", mas a pré-condição de lightOnFire precisa saber que o item está na grelha. Você nunca pode inferir isso do objeto invariante. É verdade que desde a pré e pós-condições e de um estado inicial conhecido, você pode (assumindo que a estrutura de objetos só é mutável através de métodos e as condições pré e pós descrever todas as mudanças ambientais), inferir uma invariante objeto. No entanto, isso pode ser complexo, e quando você está afirmando coisas "na linguagem", é mais fácil simplesmente fornecer tanto.
Claro, fazendo em variantes que o estado de um item de boolean é verdadeiro ou falso é um pouco inútil - é assegurado sistema tipo que
.