Upgrade to Pro — share decks privately, control downloads, hide ads and more …

GURU SP - Design de aplicações orientadas a objeto

Avatar for Elaine Naomi Elaine Naomi
October 27, 2018
99

GURU SP - Design de aplicações orientadas a objeto

Talk apresentada no Guru dia 27/10/2018

Avatar for Elaine Naomi

Elaine Naomi

October 27, 2018
Tweet

More Decks by Elaine Naomi

Transcript

  1. DEPRECATED PHOTO Elaine Naomi Watanabe Desenvolvedora de Software (Plataformatec) Mestre

    em Ciência da Computação (USP) github.com/elainenaomi twitter.com/elaine_nw
  2. quais são os conceitos básicos de orientação a objeto como

    identificar problemas na nossa base de código como melhorar o design do nosso código o que vamos ver?
  3. Ctrl + F / ⌘ + F para qualquer alteração

    Arquivos constantemente alterados
  4. Uso de Plain Old Ruby Object (PORO) Casos de uso

    Regras de negócio explícitas
  5. class ReserveBookService attr_reader :user, :book, :notification_service def initialize(user, book, notification_service)

    @user = user @book = book @notification_service = notification_service end def confirm! user.books << book notification_service.reservation_completed(user, book) end end
  6. Mais padrões Value Objects Form Objects Query Objects View Objects

    Policy Objects http://bit.ly/object_patterns
  7. class BooksUser < ApplicationRecord belongs_to: :book belongs_to: :user after_commit :send_notification_reservation_completed

    def send_notification_reservation_completed NotificationService.reservation_completed(user, book) end end
  8. class BooksUser < ApplicationRecord belongs_to: :book belongs_to: :user after_commit :send_notification_reservation_completed

    def send_notification_reservation_completed NotificationService.reservation_completed(user, book) end end
  9. Uma classe de persistência não deveria saber sobre notificações a

    um usuário, por ex. Que tal um Service Object para isso?
  10. class ReserveBookService attr_reader :user, :book, :notification_service def initialize(user, book, notification_service)

    @user = user @book = book @notification_service = notification_service end def confirm! user.books << book notification_service.reservation_completed(user, book) end end
  11. class FinancialReport def generate(account, file_format) case file_format when :csv file

    = FormatCSV.generate_file(account.transactions) when :xml file = XML.parse_list(account.transactions) end Mailer.send(account.email, file) end end
  12. class FinancialReport def generate(account, file_format) case file_format when :csv file

    = FormatCSV.generate_file(account.transactions) when :xml file = XML.parse_list(account.transactions) when :pdf file = PDFGenerator.create(account.transactions) end Mailer.send(account.email, file) end end edição
  13. class FinancialReport def generate(account, file_format) case file_format when :csv file

    = FormatCSV.generate_file(account.transactions) when :xml file = XML.parse_list(account.transactions) when :pdf file = PDFGenerator.create(account.transactions) end Mailer.send(account.email, file) end end
  14. class FileCreatorXML < FileCreator def create(items) XML.parse(items) end end class

    FileCreatorCSV < FileCreator def create(items) FormatCSV.generate_file(items) end end
  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.
  16. 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
  17. 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
  18. class PayrollAccount < CheckingAccount class OperationNotAllowed < StandardError; end #

    ... def compute_bonus raise OperationNotAllowed end end
  19. 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
  20. 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
  21. class Rectangle attr_reader :width, :height def initialize(width, height) @width =

    width @height = height end def area width * height end end
  22. class CoffeeMachine def brew_coffee # brew coffee logic end def

    fill_coffee_beans # fill coffee beans end end
  23. class Staff attr_reader :coffee_machine def initialize @coffee_machine = CoffeeMachine.new end

    def fill_coffee_beans coffee_machine.fill_coffee_beans end end
  24. class CoffeeMachineUserInterface def brew_coffee # brew coffee logic end end

    class CoffeeMachineServiceInterface def fill_coffee_beans # fill coffee beans end end
  25. class CoffeeMachineUserInterface def brew_coffee # brew coffee logic end end

    class CoffeeMachineServiceInterface def fill_coffee_beans # fill coffee beans end end
  26. class FinancialReport def generate(account, file_format) case file_format when :csv file

    = FormatCSV.generate_file(account.transactions) when :xml file = XML.parse_list(account.transactions) when :pdf file = PDFGenerator.create(account.transactions) end Mailer.send(account.email, file) end end