Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
Assistindo um hangout de princípio substituição de liskov inclusive é muito bom, com participação do joão batista
Em uma determinada hora do hangout eles falaram o seguinte sobre input e output:
INPUT(Entrada)
>
As classes derivadas não podem ser mais fortes em termos de input. E o que é ser mais forte? Não posso restringir a mais.. pq se eu colocar uma regra de restrição a mais na classe filha e não vou poder substituir esse negócio, por outra classe na hierarquia.
Exemplo:
Em um determinado cenário, um dos parâmetro de input(entrada) de uma classe é um inteiro, e a classe pai defini que esse inteiro só pode ser entre 1 a 10.. na classe filha então eu não posso restringir essa entrada por exemplo de 3 e 4, porem eu posso aumentar esse rand, como por exemplo a classe filha possa receber uma entrada de 1 a 15. Então o input ele não pode ser mais forte quando você desse a hierarquia.
OUTPUT(Saída)
>
Output e o reverso do input. O output das classes derivadas podem ser mais forte, do que a classe pai
Exemplo:
Em um determinado cenário, o output da classe pai tem que está entre 1 e 10, então por exemplo a minha classe filha pode está restrita de 3 a 5, e isso estaria respeitando o output da classe pai. Então no output as classes filhas podem ser mais restritas.
Bom.. na discussão do hangout um dos participantes, propôs o seguinte exemplo para análise, para se há ou não violação de LSP:
/*
Essa é a classe Base.. retorna estes tipos de array.
Os clientes que consomem essa classe estão esperando um retorno
de um array com index 'name' e 'age'
*/
class A
{
public function teste()
{
return ['name' => 'eu', 'age' => 15];
}
}
/*
Essa classe viola o principio LSP:
Foi adicionado um novo index no array, porem foi removido um index que a
classe Base definiu. Se um cliente acessar essa classe B e tentar acessar o index 'age'
vai dá erro, pois o cliente tinha a expectativa de que tivesse esse index 'age' no array
*/
class B extends A
{
public function teste()
{
return ['name' => 'eu', 'role' => 'Developer'];
}
}
/*
Essa classe não viola o principio LSP:
Foi adicionado mais um index no array, e não foi removido nenhum index que a classe base definiu.
pq aquilo que já esperado eu não posso remover no meu retorno.
*/
class C extends A
{
public function teste()
{
return ['name' => 'eu', 'age' => 15, 'role' => 'Developer'];
}
}
Ae eu fiquei meio que na dúvida, pois no caso do exemplo acima, a classe B ao me ver estaria sim obedecendo o output da classe pai, pois apesar da classe B remover o índice 'age', ela ainda continua com o index 'name'.. e no output como foi dito, ele pode ser mais
restritivo.. ou seja ele pode conter todos os index ou somente alguns index da classe base.
Então galera que manja no POO, estou falando besteira ou eu que não estou sabendo interpretar direito as coisas?
Alguém poderia me ajudar nessa dúvida?
hmm Ah entendi..
Só mais um detalhe. Você viu que nos exemplos das classes B e C, teve um novo índice 'role'
Devido estas classes está adicionando um novo índice na saída, também não seria uma violação?? Pois na classe base não existe este índice
Não, não é. A classe especializada não está alterando o comportamento da classe pai, apenas ampliando-a.
Seria a mesma coisa que, em um exemplo bem simplista, de uma pessoa:
class Pessoa {
private $nome;
private $endereco;
}
A classe especializada PessoaFisica adiciona o campo específico CPF:
class PessoaFisica extends Pessoa
{
private $cpf;
}
Estou adicionando um novo campo para PessoaFisica (que é inerente de uma pessoa física) e não estou alterando o comportamento do objeto Pessoa. Aonde Pessoa for requerido, pode ser facilmente substituído por PessoaFisica.
A B é uma violação da substituição de liskov (LSP) pois a restrições de range é diferente de não possuir mais um índice no array.
A LSP é mais facilmente identificada em testes. Mas pode-se utilizar analogias para identificar o problema.
Basicamente a LSP define que, se o objeto Y é um subtipo do objeto X, ele possa ser utilizado, no lugar do X, sem alteração nenhuma. É um conceito sobre comportamento e mutabilidade.
Ou seja, aonde a sua classe A for requerida, a classe B deve atender sem nenhuma alteração. O que, no exemplo, não irá acontecer, pois, um campo não existe mais.
A restrição de range (de 1 a 10 ou de 3 a 4) é diferente, pois, quem necessitar da classe Base (chamaremos de objeto X) espera que o valor seja entre 1 e 10. Já a classe especializada (chamaremos de Y), trará um valor que é de 3 a 4 (e ainda assim é dentro de 1 a 10).
Para o objeto/método/função que utilizar o objeto Y (esperando receber um tipo X), ela não precisa saber que o objeto Y irá trazer apenas valores entre 3 e 4, mas que qualquer subtipo de X deve trazer valores entre 1 e 10.