вторник, 16 мая 2017 г.

Vertical vs. Horizontal Decomposition of Responsibility

Объекты, ответственные за слишком много вещей, являются проблемой. Поскольку их сложность высока, их трудно поддерживать и расширять. Разложение ответственности - это то, что мы делаем, чтобы разбить эти чрезмерно сложные объекты на более мелкие. Я вижу два типа этой операции рефакторинга: вертикальный и горизонтальный. И я считаю, что первое лучше, чем второе.

(it is Ruby):
class Log
  def initialize(path)
    @file = IO.new(path, 'a')
  end
  def put(text)
    line = Time.now.strftime("%d/%m/%Y %H:%M ") + text
    @file.puts line
  end
end
Очевидно, объекты этого класса делают слишком много. Они сохраняют строки журнала в файле, а также форматируют их - очевидное нарушение известного принципа единственной ответственности. 

Объект этого класса будет нести ответственность за слишком много вещей. Нам нужно извлечь из него какую-то функциональность и поместить ее в другой (ие) объект(ы). Мы должны разложить  ответственность. Так будет выглядеть класс Log при извлечении:
class Log
  def initialize(path)
    @file = IO.new(path, 'a')
  end
  def put(line)
    @file.puts line
  end
end
Теперь он сохраняет только строки в файл, что идеально. Класс является сплоченным и небольшим. Давайте сделаем это:
log = Log.new('/tmp/log.txt')
Далее, куда мы помещаем строки с функциональными возможностями форматирования, которые были просто извлечены? Существует два подхода к разложению ответственности: горизонтальный и вертикальный. Эта горизонтальна
class Line
  def initialize(text)
    @line = text
  end
  def to_s
    Time.now.strftime("%d/%m/%Y %H:%M ") + text
  end
end
Чтобы использовать Log и Line вместе, мы должны сделать следующее:
log.put(Line.new("Hello, world"))
Понимаете, почему это горизонтально? Потому что этот скрипт видит их обоих. Оба они находятся на одном уровне видимости. Мы всегда должны общаться с ними обоими, когда хотим войти в журнал. Оба объекта Log и Line перед нами. Мы должны иметь дело с двумя классами, чтобы записывать строку:


А вот, это уже вертикальное разложение ответственности:
class TimedLog
  def initialize(log)
    @origin = log
  end
  def put(text)
    @origin.put(Time.now.strftime("%d/%m/%Y %H:%M ") + text)
  end
end
Класс TimedLog является декоратором, и мы используем его вместе:
log = TimedLog.new(log)
Теперь мы просто помещаем строку в журнал:
log.put("Hello, world")
Ответственность разложена по вертикали. У нас все еще есть одна точка входа в объект журнала, но объект «состоит» из двух объектов, один из которых обернут в другой:


В общем, я думаю, что горизонтальная декомпозиция ответственности - плохая идея, а вертикальная - намного лучшая. Это объясняется тем, что вертикально разложенный объект уменьшает сложность, а горизонтально разложенное фактически усложняет ситуацию, поскольку его клиенты должны иметь дело с большим количеством зависимостей и большим числом точек соприкосновения. 

Отзывы и комментарии:


Схема слоев концепции Егора по сравнению с традиционной.
 




 


Комментариев нет:

Отправить комментарий