O Princípio da Substituição de Liskov
Antes de continuarmos pelos padrões de projeto, acho importante ter aqui uma explicação sobre o Princípio da Substituição de Liskov. Ele é comum nas boas práticas de programação orientada a objetos e seus conceitos aparecem muito ao utilizar diversos padrões de projeto, principalmente no uso de Interfaces em padrões como o State (estado), o Strategy (Estratégia) ou os diversos tipos de Factories (Fábricas). Apesar de sua popularidade, ainda sim costuma dar um nó na cabeça de quem está começando.
Historicamente falando, O princípio foi introduzido em 1993 (muito recente, como podem ver) por Barbara Liskov e Jeannette Wing no artigo Family Values: A Behavioral Notion of Subtyping. Segundo ele:
Se q(x) é uma propriedade demonstrável dos objetos x de tipo T. Então q(y) deve ser verdadeiro para objetos y de tipo S onde S é um subtipo de T.
“Mas hein?!?” Apesar de parecer complicado, não é. Traduzindo isso para uma linguagem mais simples:
Se você pode chamar um método q de uma classe TMae, pode também chamar o método q de uma classe TFilha com herança de TMae.
“Bom, melhorou bastante. Mas você não pode explicar melhor não, Tiago?” Se uma classe herda de outra classe, cria-se a relação de “é um”. Explicar isso à fundo é material para um outro artigo, mas basta dizer que quando a classe TFilha herdou os métodos de TMae, ela passou a ser uma TMae estendida, melhorada (daí algumas linguagens utilizarem a palavra extends para definir herança): ela tem TUDO que uma TMae tem, além das coisas que só TFilha tem.
Se TFilha tem tudo que a TMae tem, as chamadas por TMae podem receber uma TFilha sem o menor problema. Entendamos o código abaixo:
Primeiro criamos uma classe TMae:
package Classes
{
public class TMae
{
public function TMae()
{
}
public function Voce(): void
{
trace ("Eu sou uma TMae");
}
}
}
Como TMae precisa de uma filha, vamos criá-la herdando de sua mãe:
package Classes
{
import Classes.TMae;
public class TFilha extends TMae
{
public function TFilha(): void
{
super(); // Chama o construtor da classe TMae
}
public override function Voce():void
{
trace ("Eu sou uma TFilha");
}
public function Mae():void
{
// chama o método Voce() da classe mãe
super.Voce();
}
}
}
Vale lembrar que TFilha pode ter seus extras, como fiz com o método Mae(), que exibe a mãe de filha, o método Voce() de super. Para colocar isso tudo para funcionar, precisamos da classe TMain:
package
{
import flash.display.MovieClip;
import Classes.TMae;
import Classes.TFilha;
public class TMain extends MovieClip
{
public function TMain(): void
{
var mae: TMae = new TMae();
var filha: TFilha = new TFilha();
trace ("======= MAE =======");
this.testarLiskov(mae);
trace ("======= FILHA =======");
this.testarLiskov(filha);
trace ("======= MAE DA FILHA =======");
filha.Mae();
//trace ("======= MAE DA MAE? =======");
//mae.Mae();
}
public function testarLiskov(obj:TMae)
{
obj.Voce();
}
}
}
A saída disso é a seguinte:
======= MAE ======= Eu sou uma TMae ======= FILHA ======= Eu sou uma TFilha ======= MAE DA FILHA ======= Eu sou uma TMae
Para terminar, lembrem-se que o Princípio da Substituição de Liskov não é comutativo. Ou seja: podemos trocar a TMae por uma TFilha, mas não uma TFilha por uma TMae. Se TFilha pode possuir mais métodos e atributos que TMae, não temos como chamá-los diretamente por TMae. Para confirmar, basta descomentar a linha mae.Mae() e ver que o compilador não consegue encontrar o método Mae() em TMae (claro, ele é de TFilha!).
Saiba mais sobre o Princípio na Wikipédia.
Artigos Relacionados:
Sem artigos relacionados.
4 Comments
Links to this Post
-
Tiago via Rec6 — 03/09/2009 @ 20:37
-
Marios, Máquinas de Estados e o Padrão de Projetos State – Parte 2 | Nuss... E agora?!? — 27/09/2009 @ 21:34
-
Padrão de Projetos Observer: Implementando mísseis teleguiados – parte 2 | Nuss... E agora?!? — 29/11/2009 @ 13:50
RSS feed for comments on this post. TrackBack URI

By Everton Vieira, 03/09/2009 @ 21:46
Mais um grande artigo Tiagão, o principio de Liskov, apesar de recente, é a base para muita coisa.
Ficou muito bem explicado (y)