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

Паттерны проектирования - 1.pdf

Vitaly Shlyaga
November 02, 2012
400

Паттерны проектирования - 1.pdf

Vitaly Shlyaga

November 02, 2012
Tweet

Transcript

  1. Паттерны для паттернов Отделяйте вещи, которые меняются, от тех, которые

    остаются неизменными. Программируйте интерфейсы, а не реализацию. Используйте композицию вместо наследования. Делегируйте (передавайте полномочия).
  2. Отделяйте изменяющееся от неизменного Система должна быть готова к изменениям.

    Но если изменение в А требует изменения в B, а то, в свою очередь, изменения в C и т.д. — это плохо. Если сразу определить части системы, которые могут меняться, можно отделить их от всего остального. Конечно, правки всё равно придётся вносить, но это будут правки в рамках одного конкретного модуля, а не правки размазанные по всей системе.
  3. Программируйте интерфейсы, а не реализацию if is_car my_car = Car.new

    my_car.drive(200) else my_plane = AirPlane.new my_plane.fly(200) end
  4. Используйте композицию вместо наследования class Vehicle def start_engine # Запустить

    двигатель end def stop_engine # Остановить двигатель end end class Car < Vehicle def sunday_drive start_engine # Покататься stop_engine end end Vehicle Car start_engine() stop_engine()
  5. Используйте композицию вместо наследования class Engine def start # Запустить

    двигатель end def stop # Остановить двигатель end end class Car def initialize @engine = Engine.new end def sunday_drive @engine.start # Покататься @engine.stop end end Vehicle Car start_engine() stop_engine() Engine
  6. Используйте композицию вместо наследования class Car def initialize @engine =

    GasolineEngine.new end def sunday_drive @engine.start # покататься @engine.stop end def switch_to_diesel @engine = DieselEngine.new end end
  7. Делегируйте class Car def initialize @engine = GasolineEngine.new end def

    sunday_drive @engine.start # Покататься @engine.stop end def switch_to_diesel @engine = DieselEngine.new end def start_engine @engine.start end def stop_engine @engine.stop end end
  8. Порождающие Предназначены для создания объектов, позволяя системе оставаться независимой как

    от самого процесса порождения, так и от типов порождаемых объектов.
  9. Поведенческие Цепочка обязанностей (Chain of responsibility) Команда (Command) Интерпретатор (Interpreter)

    Итератор (Iterator) Посредник (Mediator) Хранитель (Memento) Наблюдатель (Observer) Состояние (State) Стратегия (Strategy) Шаблонный метод (Template)
  10. Шаблонный метод Паттерн поведения классов, определяющий основу алгоритма и позволяющий

    наследникам переопределять некоторые шаги алгоритма, не изменяя его структуру в целом.
  11. Шаблонный метод class Report def initialize @title = 'Ежемесячный отчёт'

    @text = [ 'Всё идёт', 'очень хорошо.' ] end def output_report puts('<html>') puts(' <head>') puts(" <title>#{@title}</title>") puts(' </head>') puts(' <body>') @text.each do |line| puts(" <p>#{line}</p>" ) end puts(' </body>') puts('</html>') end end
  12. Шаблонный метод def output_report(format) if format == :plain puts("*** #{@title}

    ***") elsif format == :html puts('<html>') puts(' <head>') puts(" <title>#{@title}</title>") puts(' </head>') puts(' <body>') else raise "Unknown format: #{format}" end @text.each do |line| if format == :plain puts(line) else puts(" <p>#{line}</p>" ) end end if format == :html puts(' </body>') puts('</html>') end end
  13. Шаблонный метод Вывести начальную служебную информацию, которая требуется в соответствии

    с форматом. Вывести заголовок отчёта. Вывести каждую строчку отчёта. Вывести конечную служебную информацию, которая требуется в соответствии с форматом.
  14. Шаблонный метод def output_body @text.each do |line| output_line(line) end end

    def output_start raise 'Вызван абстрактный метод: output_start' end def output_head raise 'Вызван абстрактный метод: output_head' end def output_body_start raise 'Вызван абстрактный метод: output_body_start' end def output_line(line) raise 'Вызван абстрактный метод: output_line' end def output_body_end raise 'Вызван абстрактный метод: output_body_end' end def output_end raise 'Вызван абстрактный метод: output_end' end
  15. Шаблонный метод class HTMLReport < Report def output_start puts('<html>') end

    def output_head puts(' <head>') puts(" <title>#{@title}</title>") puts(' </head>') end def output_body_start puts('<body>') end def output_line(line) puts(" <p>#{line}</p>") end
  16. Шаблонный метод class PlainTextReport < Report def output_start end def

    output_head puts("**** #{@title} ****") end def output_body_start end def output_line(line) puts(line) end
  17. Шаблонный метод В базовом классе находится базовый алгоритм. Подклассы реализуют

    различное поведение, изменяя составные части базового алгоритма. Базовый класс может не реализовывать детали функционала, а только реализовывать базовый алгоритм — в таком случае детали полностью лежат на подклассах. Либо базовый класс может представлять реализацию по-умолчанию, которую подклассы могут переопределять.
  18. Стратегия Паттерн поведения классов, предназначенный для определения семейства алгоритмов, инкапсуляции

    каждого из них и обеспечения их взаимозаменяемости. Позволяет менять выбранный алгоритм независимо от объектов-клиентов, которые его используют.
  19. Стратегия Если после создания отчёта в объекте класса HTMLReport мы

    вдруг передумаем и захотим вывести отчёт в виде текста, нам придётся создавать полностью новый объект класса PlainTextReport.
  20. Стратегия class Formatter def output_report( title, text ) raise 'Вызван

    абстрактный метод' end end class HTMLFormatter < Formatter def output_report( title, text ) puts('<html>') puts(' <head>') puts(" <title>#{title}</title>") puts(' </head>') puts(' <body>') text.each do |line| puts(" <p>#{line}</p>" ) end puts(' </body>') puts('</html>') end end
  21. Стратегия class Report attr_reader :title, :text attr_accessor :formatter def initialize(formatter)

    @title = 'Ежемесячный отчёт' @text = [ 'Всё идёт', 'очень хорошо.' ] @formatter = formatter end def output_report @formatter.output_report( @title, @text ) end end report = Report.new(HTMLFormatter.new) report.output_report report.formatter = PlainTextFormatter.new report.output_report
  22. Стратегия class Report attr_reader :title, :text attr_accessor :formatter def initialize(formatter)

    @title = 'Ежемесячный отчёт' @text = ['Всё идёт', 'очень хорошо.'] @formatter = formatter end def output_report() @formatter.output_report(self) end end
  23. Стратегия class Report attr_reader :title, :text attr_accessor :formatter def initialize(&formatter)

    @title = 'Ежемесячный отчёт' @text = [ 'Всё идёт', 'очень хорошо.' ] @formatter = formatter end def output_report @formatter.call( self ) end end
  24. Стратегия HTML_FORMATTER = Proc.new do |context| puts('<html>') puts(' <head>') puts("

    <title>#{context.title}</title>") puts(' </head>') puts(' <body>') context.text.each do |line| puts(" <p>#{line}</p>" ) end puts(' </body>') puts end report = Report.new &HTML_FORMATTER report.output_report
  25. Стратегия Решает те же задачи, что и «Шаблонный метод», но

    с помощью делегирования, а не наследования. Позволяет на лету менять поведение «главного» объекта, выбирая разные объекты-стратегии. Можно передавать отдельные параметры в стратегию или сам экземпляр главного объекта. В Ruby удобно «стратегии» реализовывать с помощью Proc-объектов.
  26. Задачи Реализовать класс Math, который принимает 2 параметра (два числа)

    и выполняет некоторую математическую операцию (def calculate) над ними. С помощью паттернов Template Method и Strategy реализовать сложение, умножение и возведение в степень этих чисел. Реализовать класс Math «в стиле Ruby», используя Proc для передачи алгоритма в контекст.