Принцип единой ответственности и рефакторинг метода Move

Кажется, я застрял между двумя рекомендациями по дизайну.

У меня есть класс, представляющий трехмерный объем, состоящий из блоков. Этот класс предоставляет простые методы модификации, такие как AddBlock или RemoveBlock.

Есть несколько вещей, которые мне нужно сделать с этим классом

Во-первых, мне нужно знать определенные совокупные свойства тома с помощью таких методов, как GetTotalWeight или GetMaximumWidth.

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

У меня вопрос: если я добавлю эти методы запроса и преобразования в класс Volume, нарушит ли это принцип единой ответственности? Моими обязанностями на занятиях будут:

  • Храните объемные данные, позволяя выполнять простые модификации (добавлять и удалять блоки)
  • Предоставление сводной информации об объеме
  • Предоставьте возможности преобразования для этих томов.

Если я решу, что это слишком большая ответственность и что класс Volume должен просто представлять объем, мне нужно будет создать такие классы, как VolumeTrimmer, VolumeShrinker и т. д. для преобразований и WeightCalculator для запросов.

Этот последний вариант, по-видимому, аккуратно разделяет проблемы в разных классах. Однако, если я посмотрю на детали Trim(Volume v) моего VolumeTrimmer, все, что он делает, это вызывает операции над объемом. В то же время метод CalculateWeight(Volume v) моего WeightCalculator, по-видимому, больше всего связан с Volume.

Когда я смотрю на такой метод, я чувствую необходимость использовать рефакторинг Move Method. Я смотрю на код и говорю: «Этот метод в основном связан со свойствами другого класса, поэтому мне лучше перенести этот метод в этот класс». Но это возвращает ответственность классу Volume!

Любые идеи о том, как мне подойти к этой проблеме? Я неправильно понимаю эти рекомендации?


person Eduardo Vila-Echague    schedule 09.09.2014    source источник
comment
Класс Volume кажется мне странным. Объем — это свойство чего-то, например, структуры.   -  person Sam Holder    schedule 09.09.2014
comment
@Sam: он имеет в виду объем, то есть трехмерную область пространства   -  person John Saunders    schedule 09.09.2014


Ответы (3)


Как обычно, единственный правильный ответ на этот вопрос: это зависит.

Часто имеет смысл иметь классы, которые являются простыми контейнерами данных, такими как ваш класс объема, без методов сжатия, обрезки и т. д.

Существует также возможность использовать Trimmer и Shrinker только внутри класса Volume. Таким образом, у вас есть том и его операции, красиво упакованные в один класс, но также и сложные методы, которые могут, например, помочь в тестировании.

Итак, как решить, какой дизайн является правильным? Вот пара наводящих вопросов:

  1. Для Shrinker и т. д. вам нужно сделать общедоступными данные в классе Volume, которые в противном случае были бы закрытыми? Если это так, это намекает на методы Volume

  2. Можно ли представить себе альтернативную реализацию для Shrinker&Co, возможно, в целях тестирования или с другими характеристиками? Если это так, это намекает на отдельные классы.

  3. Использует ли клиент Volume большую часть времени методы add/removeBlock И метод сжатия И обрезки? Это снова намекает на один класс.

  4. Нужен ли Shrinker&Co только подмножество API Volume? Если это так, это намекает на отдельные классы.

person Jens Schauder    schedule 09.09.2014
comment
Спасибо за такой исчерпывающий ответ. Я думал, что ответ будет большим «зависит», но мне нужно было убедиться. Я буду иметь в виду ваши примеры, когда буду двигаться дальше. - person Eduardo Vila-Echague; 10.09.2014

Насколько я понимаю, принцип единой ответственности довольно условен, так как ни один фрагмент кода из языка более высокого уровня не может делать только одну вещь. При этом кажется, что ваши VolumeTrimmer и VolumeShrinker заинтересованы только в подмножествах свойств Volume. Поэтому имеет смысл разделить эти классы и предоставить им только то подмножество свойств, которое их интересует. Это позволяет повторно использовать их в других сценариях, где другой класс также имеет это подмножество и желает того же поведения, но ему не нужно ничего знать. о Том. Имеет смысл?

person Guillaume CR    schedule 09.09.2014

Я не вижу в этом проблемы. Похоже, это пример шаблона Composite. Ваш объем состоит из блоков.

Нет никаких причин, по которым ваш том не может выполнять операции на уровне тома, такие как Transform, которые могут быть реализованы путем делегирования операциям Transform на уровне блоков.

person John Saunders    schedule 09.09.2014