As mudanças no desempenho violam o princípio da substituição de Liskov?

14

Diga que tenho:

interface Thing
{
    GetThing();
}

class FastThing : Thing 
{
    public int GetThing()
    {
        return 1;
    }
}

class SlowThing : Thing
{
    public int GetThing()
    {
        return GetThingFromDatabase();
    }
}

Isso é uma violação do princípio da substituição de Liskov?

ConditionRacer
fonte
GetThingFromDatabase()não é lento o suficiente para tornar isso controverso. Factor4096BitPublicKey();return 1;tornaria as coisas um pouco mais interessantes.
10243 Patrick
1
Se você substituir FastThingpor SlowThing, o LSP não se aplicará. Se você adicionar um comentário ao Thing::GetThingqual diz "É muito rápido", a questão poderá ser discutida.
Cefalópode #

Respostas:

14

Isso realmente depende. Algumas interfaces têm, por exemplo, restrições de complexidade (elas obviamente não podem ser aplicadas programaticamente). O caso mais básico é "GetThing () fornece um int- ou seja, ele pára"; nesse caso, a resposta seria "Não" - ambas as versões do GetThing () param e retornam um int.

Mas muitas interfaces têm garantias de desempenho implícitas ou expressamente declaradas, seja em complexidade ou em tempo fixo. Por exemplo, no padrão C ++, é ilegal implementar a biblioteca com uma chamada de bloqueio, exceto onde o padrão o permitir expressamente.

DeadMG
fonte
3
O desempenho não é algo obrigatório através de uma verificação de tipo. É uma promessa do implementador / mantenedor da biblioteca.
dietbuddha
3
Eu afirmei explicitamente isso na minha resposta?
DeadMG
1
Meu argumento foi que, assim que você incluir algo diferente de digitar nos critérios, não estará mais falando sobre Liskov, pois é específico para digitar. Embora a "prática" de não subdividir objetos com desempenho diferente possa ser boa, Liskov não tem nada a dizer sobre isso.
dietbuddha
7
Liskov afirma que, para os Derivados, deve ser utilizável em qualquer lugar que uma Base esteja. Isso pode não ser verdade se a Base garantir certos desempenhos ou características. Por exemplo, se blocos Derivados, pode haver potencial para conflitos.
111313 DeadMG
8

TL; DR: Não

De acordo com a "Subtipagem Comportamental Usando Invariantes e Restrições" (a formalização do princípio), ela se preocupa principalmente com as propriedades de "segurança" de um tipo de objeto. Propriedades que governam a substituibilidade apenas dentro do contexto das informações de tipo. Um tipo de objeto é ortogonal ao seu desempenho. Portanto, uma diferença de desempenho não é uma violação do Princípio de Substituição de Liskov.

dietbuddha
fonte
3
Dei uma breve olhada nesse artigo, mas você tem certeza de que restrições de tempo não podem ser formalmente prováveis? E mesmo que Liskov não quis dizer isso em palavras, incluir restrições de tempo pode ser visto como uma boa extensão do LSP clássico, que pode ser relevante para a programação do mundo real.
Doc Brown
@ Brown Doc: se o tempo é útil como uma consideração para substituir um objeto ou não é ortogonal para Liskov. Pode adicioná-lo como um preceito esperto, mas não pode e nunca fará parte de Liskov. É como ter uma equação lógica booleana e dizer: False só pode ser substituído por True se for rápido o suficiente. A velocidade não tem nada a ver com matemática ou lógica.
dietbuddha
Contra-exemplo: esse código é chamado no EDT do Java ou no loop de eventos do Node. O desempenho radicalmente mais lento da versão lenta irá semi-quebrar o software. Penso que a resposta adequada a esta pergunta é "provavelmente não, mas há exceções".
user949300
6

Que garantias a interface oferece? Como GetThingnão dá garantias, os subtipos não precisam respeitá-lo.

Se a interface era algo como GetThingInLinearTimeou se o tipo base é virtual e a implementação padrão é uma complexidade, em seguida, fazendo que a complexidade algorítmica pior seria violar LSP.

Telastyn
fonte
4

O desempenho do software não tem nada a ver com o Princípio de Substituição de Liskov.

O princípio tem a ver com a substituição de subtipos e o impacto comportamental de substituir esse objeto apenas em termos de POO.

A entrada e a saída de getThing()permanecem as mesmas nos dois casos e, lenta e rapidamente, provavelmente colocam os objetos no mesmo estado.

Reactgular
fonte
1

Importa o que o próprio Princípio de Substituição de Liskov diz especificamente? Se um subtipo viola as expectativas do consumidor do supertipo, isso parece uma coisa ruim, independentemente de o LSP ser mais restritivo.

Portanto, na minha opinião, se todas as expectativas razoáveis ​​do consumidor de uma abstração são cumpridas pelo subtipo parece ser uma boa generalização do LSP.

No entanto, no exemplo que você postou e com interfaces Java em geral, não está claro que o consumidor da Thinginterface tenha qualquer expectativa razoável de que deve ser rápida ou lenta. Se os javadocs da interface incluírem linguagem sobre quais operações prometem ser rápidas, pode haver um argumento para um problema com base no desempenho. Mas a convenção Java é certamente que várias implementações têm características de desempenho diferentes.

trptcolina
fonte
2
Até onde eu sei, o exemplo postado não é Java #
30613
0

O tio Bob respondeu a uma pergunta muito semelhante em que afirma que uma violação do LSP exige três partes:

O tipo T, o subtipo S e o programa P que usa T, mas recebem uma instância de S.

Atrevo-me a supor que essa pergunta tenha uma estrutura semelhante à que ele respondeu, na medida em que não menciona o P que está usando o T e que comportamento o P espera.

Você pode encontrar a resposta dele aqui . (Você precisará rolar para baixo alguns e procurar a resposta do usuário chamado Robert Martin)

TMc
fonte
1
Como isso responde à pergunta?
Gnat #
@gnat Porque a pergunta, como feita, está incompleta. São necessárias três partes para determinar uma violação do LSP. Das quais, ele apenas forneceu 2 das partes.
TMc 6/09/13