Вспомогательный класс (ы) против функционального наследования. Лучшая практика - PullRequest
7 голосов
/ 17 июня 2010

У меня есть классы команд, которые реализуют интерфейс ICommand {Execute}. Несколько команд имеют дубликаты кода. У меня есть несколько вариантов, как высушить:

  • Создать статический вспомогательный класс (классы) и переместить туда дублирующий код
  • Создание наследования команд с защищенными вспомогательными методами

Что бы вы предложили и почему?

ДОБАВЛЕНО Спасибо всем, кто ответил, многие ответы были одинаковыми и полезными!

Ответы [ 8 ]

5 голосов
/ 17 июня 2010

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

3 голосов
/ 18 июня 2010

Это полностью зависит от характера вашего дублированного кода.

Каковы входы / выходы ваших вспомогательных функций? Они работают с логически связанным набором переменных? Тогда - да, вам лучше создать базовый класс с этими переменными в качестве членов и соответствующим набором вспомогательных функций.

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

3 голосов
/ 17 июня 2010

По моему мнению, я бы поместил дубликат кода в базовый класс, если он относится только к этой иерархии классов и не будет использоваться вне его. Если есть возможность использования кода в разных классах, переместите его в вспомогательный класс в общем проекте.

Наслаждайтесь!

3 голосов
/ 17 июня 2010

Если есть вероятность, что дублирующая логика может понадобиться и другим классам вне иерархии, я бы поместил ее в статические вспомогательные классы. В противном случае в базовом классе с защищенным наследованием.

1 голос
/ 27 сентября 2016

Использование помощников в вашем собственном коде - плохая практика из-за лени.

Единственная возможная ситуация, в которой вам действительно нужны помощники, - это расширение поведения закрытых классов из сторонних библиотек, таких как селен и т. Д.

Что такое помощник?Это статический метод, который находится где-то из самого класса.

Какие проблемы у нас возникают?

  1. статический метод.Есть проблемы с юнит-тестированием.Например, наши разработчики добавили кеширование для помощников.В результате не было возможности просто издеваться над этими методами, в то время как мне приходилось добавлять много логики только для простого насмешки.Да, есть вероятность неправильного использования статического метода ... но в начале никто не ожидал добавить состояние к помощнику.
  2. location.Метод находится в другом классе, далеко от базовой логики.Это неправильная концепция дизайна кода.

Когда использовать помощника?Когда вам нужно расширить стороннюю библиотеку без возможности наследовать ее.В противном случае просто наследуйте lib.

Когда не используете помощников?Уменьшить дублированный код.Вам нужно переместить этот код в другой сервис.Прочитайте о DDD, чтобы улучшить навыки рефакторинга и узнать, как лучше организовать обслуживание

1 голос
/ 17 июня 2010

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

Если у вас есть код, который является общим только для подмножеств несвязанных команд, и создание иерархии наследования приведет к форсированию несуществующих отношений, то добавление в класс «помощника» (нестатический, если это возможно) , чтобы улучшить тестируемость) было бы совершенно естественным способом решения этой проблемы. Вы можете обнаружить, что вы можете сгруппировать «вспомогательные» методы естественным образом в свои собственные классы. Например, если нескольким методам необходимо взаимодействовать с вашей подсистемой аутентификации, у вас может быть AuthenticationMediator для этих методов. Я также не вижу никаких конфликтов с выполнением некоторых из них.

0 голосов
/ 27 ноября 2014

Помощники кода без сохранения состояния.

Код, зависящий от состояния, с несколькими методами, использующими наследование.Например, когда несколько методов используют переменную общего члена и, таким образом, поддерживают общее состояние.

Цель состоит в том, чтобы уменьшить объем дублирующегося кода, и это зависит от того, какой это тип кода.Однако я действительно ненавижу, когда люди переусердствуют с этим и делают супер абстрактные классы или вспомогательные функции, которые делают 7 переходов к другому удушающему абстрактному коду, который называется что-то вроде "Executor", Invoker "" DataConveyer "" DataManager "" SharedCode ".И что каким-то образом в конце всех этих скачков действительно удалось выполнить работу, которую предполагалось, но она настолько взаимосвязана друг с другом, что вы не уверены, где внести новые изменения, чтобы добавить эту новую функцию.Должен ли я сделать это DataConveyer или я должен сделать это в DataManager?

Таким образом, золотая цель должна быть, будьте проще.

0 голосов
/ 17 июня 2010

Если логика работает с интерфейсом элементами, в отличие от реализации членов, то рекомендуется написание вспомогательного метода [или метода расширения].

public IRandom
{
    byte NextByte ();
}

public static class IRandomExtensions
{
    // logic that acts against public interface IRandom
    // may be applied to all implementations
    public static int GetNextUnbiasedInteger (this IRandom random) { }
    public static IEnumerable<T> Shuffle<T> (
        this IRandom random, 
        IEnumerable<T> items) { }
}

Если бизнес-логика работает против реализации членов,

public class SomeCommand : ICommand
{
    // an implementation-specific member, NOT a member
    // of ICommand
    public int SomeControlCount { get; set; }
}

// a method that references implementation-speciic
// details. where should this go?
public void DoSomething ()
{
    SomeCommand command;
    int count = command.SomeControlCount;
}

тогда, вероятно, нам следует более тесно связать это с реализующим классом. Если это достаточно распространенное явление, тогда может иметь смысл базовый класс.

Лично сложные иерархии доставляют больше хлопот, чем стоят, используйте свое собственное суждение относительно удобства обслуживания, удобочитаемости и повторного использования, и с вами все должно быть в порядке!

Надеюсь, это поможет! :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...