- Criar uma classe Pessoa, com propriedade nome e um método que retorna suas propriedades em um Set, nesse caso, apenas nome.
using System;
using System.Collections.Generic;
namespace LSP
{
public class Pessoa
{
public string Nome { get; set; }
}
}
public class Impressao
{
public void Imprimir(Pessoa pessoa)
{
Console.WriteLine(pessoa.Nome);
}
}
}
- No Program.cs vamos criar duas instancias de Pessoa e utilizar a Classe Impressao para exibir seus nomes no console.
using System;
namespace LSP
{
class Program
{
static void Main(string[] args)
{
var p1 = new Pessoa() { Nome = "Elliot" };
var p2 = new Pessoa() { Nome = "Mr. Robot" };
var impressao = new Impressao();
impressao.Imprimir(p1);
Console.WriteLine(" ");
impressao.Imprimir(p2);
Console.ReadLine();
}
}
}
Out:
Elliot
Mr. Robot
- Agora imagine que o projeto tem que ser alterado, para que Pessoa seja divido em Física e Jurídica e então decidimos extender essa classe em PessoaFisica e PessoaJuridica
public class PessoaJuridica: Pessoa
{
// Herda Nome
public string RazaoSocial { get; set; }
public string CNPJ { get; set; }
}
public class PessoaFisica : Pessoa
{
// Herda Nome
public string CPF { get; set; }
}
- Agora mudamos a Main para receber uma pessoa Jurídica
using System;
namespace LSP
{
class Program
{
static void Main(string[] args)
{
var pj = new PessoaJuridica() {
Nome = "Evil Corp.",
RazaoSocial = "Evil Corporation",
CNPJ = "123"
};
var impressao = new Impressao();
impressao.Imprimir(pj);
Console.ReadLine();
}
}
}
Out:
Evil Corp.
PROBLEMA: Se quisermos exibir a Razão Social- ou outros atributos específicos de uma das classes subtipo - no mesmo método, teremos que alterar o método de impressão. Porém se alterarmos o método para exibir pessoa.RazaoSocial a Classe Pessoa não possui essa propriedade e se alterarmos para receber PessoaJuridica como parâmetro não conseguiremos receber PessoaFisica.
O LSP diz que se recebermos uma Classe Pessoa como parâmetro do método .Imprimir(), o comportamento deverá ser o mesmo para PessoaFisica e para PessoaJuridica. Então temos que garantir que ao imprimirmos as informações de ambas as subclasses de Pessoa o comportamento seja o mesmo.
- Para garantir que ao chamarmos o método impressão o comportamento será o mesmo para todas as Classes, iremos criar em ambas classes uma propriedade List que irá guardar todas as informações da mesma - é possivel utilizar o método .ToString() da Classe Object da qual todos os objetos herdam caso seja necessário guardar valores númericos ou de tipos que não são cadeia de caracteres.
using System;
using System.Collections.Generic;
namespace LSP
{
public class Pessoa
{
public string Nome { get; set; }
// Obs: A keyword virtual significa que ele pode ser rescrito
public virtual List<string> RetornarDadosPessoa()
{
var retorno = new List<string>();
retorno.Add(Nome);
return retorno;
}
}
public class PessoaJuridica: Pessoa
{
public string RazaoSocial { get; set; }
public string CNPJ { get; set; }
public override List<string> RetornarDadosPessoa()
{
// O override em C# recebe o comportamento da classe Pai
// ao instanciala na variavel retorno e depois adiciona os
// comportamentos abaixo extendendo-a
var retorno = base.RetornarDadosPessoa();
retorno.Add(RazaoSocial);
retorno.Add(CNPJ);
return retorno;
}
}
public class PessoaFisica : Pessoa
{
public string CPF { get; set; }
public override List<string> RetornarDadosPessoa()
{
var retorno = base.RetornarDadosPessoa();
retorno.Add(CPF);
return retorno;
}
}
}
- Alterar o método Impressao para imprimir todos os dados - ou os que queremos.
public class Impressao
{
public void Imprimir(Pessoa pessoa)
{
var dados = pessoa.RetornarDadosPessoa();
foreach (var s in dados)
{
Console.WriteLine(s);
}
}
}
- Então podemos alterar nossa Main para instanciar uma PessoaFisica e uma PessoaJuridica e imprimir as informações da mesma.
using System;
namespace LSP
{
class Program
{
static void Main(string[] args)
{
var pj = new PessoaJuridica() {
Nome = "Evil Corp.",
RazaoSocial = "Evil Corporation",
CNPJ = "123"
};
var pf = new PessoaFisica() {
Nome = "Elliot",
CPF = "123"
};
var impressao = new Impressao();
impressao.Imprimir(pj);
Console.WriteLine(" ");
impressao.Imprimir(pf);
Console.ReadLine();
}
}
}
Out:
Evil Corp
Evil Corporation
123
Elliot
123
Assim podemos atestar que o método .Imprimir() que recebe a Classe Pessoa tem o mesmo comportamento para seus subtipos/subclasses PessoaFisica e PessoaJuridica, cumprindo com o Principio de Substituição de Liskov.