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

Паттерны проектирования 3

Vitaly Shlyaga
November 16, 2012

Паттерны проектирования 3

Паттерны Итератор и Команда.

Vitaly Shlyaga

November 16, 2012
Tweet

More Decks by Vitaly Shlyaga

Other Decks in Education

Transcript

  1. Итератор Поведенческий паттерн проектирования, позволяющий получить последовательный доступ к элементам

    объекта-агрегата без использования описаний каждого из объектов, входящих в состав агрегации. пятница, 16 ноября 12 г.
  2. Итератор class ArrayIterator def initialize(array) @array = array @index =

    0 end def has_next? @index < @array.length end def item @array[@index] end def next_item value = @array[@index] @index += 1 value end end array = ['красный', 'зелёный', 'синий'] i = ArrayIterator.new(array) while i.has_next? puts("элемент: #{i.next_item}") end пятница, 16 ноября 12 г.
  3. Итератор def for_each_element(array) i = 0 while i < array.length

    yield(array[i]) i += 1 end end a = [10, 20, 30] for_each_element(a) { |elem| puts elem } пятница, 16 ноября 12 г.
  4. Внешний vs. Внутренний В случае внешнего итератора клиент управляет потоком.

    Пока клиент не готов, он не будет запрашивать .next. Внутренний итератор непреклонно выдаёт элементы, не обращая внимание на желания клиента. пятница, 16 ноября 12 г.
  5. Внешний vs. Внутренний def merge(array1, array2) merged = [] iterator1

    = ArrayIterator.new(array1) iterator2 = ArrayIterator.new(array2) while iterator1.has_next? and iterator2.has_next? if iterator1.item < iterator2.item merged << iterator1.next_item else merged << iterator2.next_item end end while iterator1.has_next? merged << iterator1.next_item end while iterator2.has_next? merged << iterator2.next_item end merged end пятница, 16 ноября 12 г.
  6. Ruby-style итератор class Account attr_accessor :name, :balance def initialize(name, balance)

    @name = name @balance = balance end def <=>(other) balance <=> other.balance end end class Portfolio include Enumerable def initialize @accounts = [] end def each(&block) @accounts.each(&block) end def add_account(account) @accounts << account end end пятница, 16 ноября 12 г.
  7. Ахтунг! array=['красный', 'зелёный', 'синий', 'жёлтый'] array.each do | color |

    puts(color) if color == 'зелёный' array.delete(color) end end # => красный # => зелёный # => жёлтый пятница, 16 ноября 12 г.
  8. Итератор Внешний итератор работает с коллекцией объектов, предоставляя желающим удобно

    получать её элементы. Внутренний итератор получает блок кода, который последовательно применяет к коллекции. В Ruby для реализации внутренних итераторов разумно будет использовать возможности модуля Enumerable. Если вы одновременно итерируете по коллекции и меняете её состав — будьте готовы к неприятным неожиданностям. пятница, 16 ноября 12 г.
  9. Команда class SlickButton # # Много кода, который красиво #

    рисует кнопку... # def on_button_push # # Что-то сделать. # end end пятница, 16 ноября 12 г.
  10. Команда class SaveButton < SlickButton def on_button_push # # Сохранить

    текущий документ... # end end class NewDocumentButton < SlickButton def on_button_push # # Создать новый документ... # end end пятница, 16 ноября 12 г.
  11. Команда class SlickButton attr_accessor :command def initialize(command) @command = command

    end # Много кода, который красиво рисует кнопку def on_button_push @command.execute if @command end end class SaveCommand def execute # ... end end save_button = SlickButton.new(SaveCommand.new) пятница, 16 ноября 12 г.
  12. Команда class SlickButton attr_accessor :command def initialize(&block) @command = block

    end # Много кода, который красиво рисует кнопку... def on_button_push @command.call if @command end end new_button = SlickButton.new do # Создать новый документ... end пятница, 16 ноября 12 г.
  13. Команда-2 class CreateFile < Command def initialize(path, contents) super("Создать файл:

    #{path}") @path = path @contents = contents end def execute f = File.open(@path, "w") f.write(@contents) f.close end end пятница, 16 ноября 12 г.
  14. Команда-2 class DeleteFile < Command def initialize(path) super("Удалить файл: #{path}")

    @path = path end def execute File.delete(@path) end end пятница, 16 ноября 12 г.
  15. Команда-2 class CopyFile < Command def initialize(source, target) super("Скопировать файл:

    #{source} в #{target}") @source = source @target = target end def execute FileUtils.copy(@source, @target) end end пятница, 16 ноября 12 г.
  16. Команда-2 class CompositeCommand < Command def initialize @commands = []

    end def add_command(cmd) @commands << cmd end def execute @commands.each {|cmd| cmd.execute} end def description description = '' @commands.each {|cmd| description += cmd.description + "\n"} description end end пятница, 16 ноября 12 г.
  17. Команда-2 cmds = CompositeCommand.new cmds.add_command(CreateFile.new('file1.txt', "hello world\n")) cmds.add_command(CopyFile.new('file1.txt', 'file2.txt')) cmds.add_command(DeleteFile.new('file1.txt'))

    cmds.execute puts(cmds.description) # Создать файл: file1.txt # Скопировать файл: file1.txt в file2.txt # Удалить файл: file1.txt пятница, 16 ноября 12 г.
  18. Команда-3 class CreateFile < Command def initialize(path, contents) super "Создать

    файл: #{path}" @path = path @contents = contents end def execute f = File.open(@path, "w") f.write(@contents) f.close end def unexecute File.delete(@path) end end пятница, 16 ноября 12 г.
  19. Команда-3 class DeleteFile < Command def initialize(path) super "Удалить файл:

    #{path}" @path = path end def execute if File.exists?(@path) @contents = File.read(@path) end f = File.delete(@path) end def unexecute if @contents f = File.open(@path,"w") f.write(@contents) f.close end end end пятница, 16 ноября 12 г.
  20. Команда-3 class CompositeCommand < Command # ... def unexecute @commands.reverse.each

    { |cmd| cmd.unexecute } end # ... end пятница, 16 ноября 12 г.
  21. Команда С помощью паттерна «Команда» можно создавать объекты, которые знают

    как выполнять некие действия. Паттерн полезен, чтобы создавать списки действий, которые должна сделать программа и чтобы отменять эти действия. пятница, 16 ноября 12 г.
  22. Задача 1 Реализовать класс студент, обладающий свойствами «ФИО» и «Балл».

    Реализовать класс группа, который включает в себя массив студентов. Реализовать внутренний итератор в классе группа, который позволит проводить итерацию по студентам, находящимся в группе. Можно использовать модуль Enumerable. пятница, 16 ноября 12 г.
  23. Задача 2 Входные данные — массив, содержащий различные числа и

    слова. В качестве атомарных команд реализовать: умножение всех числовых элементов массива на 2; возведение всех численных элементов массива в квадрат; «разворот» всех строковых элементов массива задом наперёд. Используя паттерн Composite, реализовать систему, позволяющую конструировать из базовых команд различные составные, сложные команды, объединяющие базовые команды в различных комбинациях. С помощью паттерна команда реализовать возможность применения команд и отката их применения (undo). пятница, 16 ноября 12 г.