O documento discute o Princípio da Substituição de Liskov (LSP), que estabelece que subclasses devem ser substituíveis por suas superclasses sem alterar as propriedades desejadas do programa. O LSP é importante para manter a correção do comportamento quando se usa herança e polimorfismo. Classes derivadas devem respeitar os contratos definidos pelas classes base para não violar o princípio.
15. Liskov Substitution Principle (1987)
Let φ(x) be a property provable about objects x
of type T. Then φ(y) should be true for objects y
of type S where S is a subtype of T.
17. Liskov Substitution Principle (1987)
Let φ(x) be a property provable about objects x
of type T. Then φ(y) should be true for objects y
of type S where S is a subtype of T.
19. Teoria dos Tipos
Como representar caracteres, números inteiros e de ponto
flutuante, booleanos no nível do processador?
Abstrações! E não pensar em bits e bytes!
E cada tipo tem suas restrições/comportamentos
20. Tipos Abstratos de Dados
Conjunto de comportamentos/operações
Estrutura de dados específica (atributos)
Como representar elementos do domínio de negócio
21. Tipos Abstratos de Dados
Conjunto de comportamentos/operações
Estrutura de dados específica (atributos)
Como representar elementos do domínio de negócio
CLASSES
24. Liskov Substitution Principle (1987)
Let φ(x) be a property provable about objects x
of type T. Then φ(y) should be true for objects y
of type S where S is a subtype of T.
"SUBCLASSES"
26. Liskov Substitution Principle (1987)
Traduzindo:
Preciso garantir que se eu substituir um objeto de uma classe por um
outro objeto de uma subclasse dessa classe, as propriedades que
definem o objeto-pai precisam continuar funcionando.
28. Herança: herança de comportamentos de
uma super classe
Polimorfismo: definição de uma interface única para
acessar tipos diferentes de objetos
29. ALERTA!
Cuidado com interpretações equivocadas sobre LSP:
Se uma subclasse altera o comportamento da superclasse,
nem sempre é uma violação desse princípio
Podemos e devemos usar o polimorfismo
(mas com sabedoria)
32. Pré-condições: dados de entrada
classes derivadas só podem ser mais permissivas
Pós-condições: dados de saída
classes derivadas só podem ser mais restritivas
Não podemos criar comportamentos inesperados ou incorretos!
O comportamento da super classe precisa ser mantido
33. class CheckingAccount
# ...
def deposit(value)
raise InvalidValueError if value <= 0
self.balance = self.balance + value
end
def compute_bonus
self.balance = self.balance * 1.01
end
end
34. class PayrollAccount < CheckingAccount
class OperationNotAllowed < StandardError; end
# ...
def compute_bonus
raise OperationNotAllowed
end
end
38. class PayrollAccount < CheckingAccount
# ...
def deposit(value)
raise InvalidValueError if value <= 100
self.balance = self.balance + value
end
def compute_bonus
self.balance = self.balance * 1.01
end
end
39. class PayrollAccount < CheckingAccount
# ...
def deposit(value)
raise InvalidValueError if value <= 100
self.balance = self.balance + value
end
def compute_bonus
self.balance = self.balance * 1.01
end
end
contrato quebrado
42. class Rectangle
attr_reader :width, :height
def initialize(width, height)
@width = width
@height = height
end
def area
width * height
end
end
43. class Square < Rectangle
attr_reader :width, :height
def initialize(width)
@width = width
@height = width
end
end
contrato quebrado
44. O que a gente precisa lembrar sobre esse princípio?
Interfaces/Abstração de comportamentos
Polimorfismo
Design by contract
Nem tudo que parece herança deveria ser uma herança