Что касается прекрасного ответа Карла Манастера, есть некоторые недостатки, которые вы должны хотя бы рассмотреть, прежде чем встать на путь, предложенный Карлом.
Наиболее значимым из них является следующее: мы используем инкапсуляцию, чтобы минимизировать количество потенциальных зависимостей, которые несут наибольшую вероятность распространения изменений. В вашем случае вы инкапсулировали закрытые методы внутри вашего класса: они не доступны другим классам и, следовательно, от них нет потенциальных зависимостей: стоимость любых изменений, которые вы вносите в них, сводится к минимуму и имеет низкую вероятность распространения на другие. классы.
Кажется, что Карл предлагает перенести некоторые частные методы из вашего класса в новый класс и сделать эти методы общедоступными (чтобы вы могли их протестировать). (Кстати, почему бы просто не сделать их публичными в исходном классе?)
Делая это, вы устраняете барьер для формирования зависимостей других классов от этих методов, что потенциально увеличивает затраты на изменение этих методов, если любой другой класс их использует.
Вы можете судить об этом нижестоящем несовершеннолетнем и о достойной цене, чтобы заплатить за то, что вы можете проверить ваши личные методы, но, по крайней мере, об этом должны знать. В небольшом числе случаев это действительно может быть целесообразно, но если вы введете это во всей своей кодовой базе, то вы резко увеличите вероятность того, что эти зависимости сформируются, увеличивая стоимость вашего цикла обслуживания до неизвестной степени.
По этим причинам я не согласен с Карлом в том, что его предложение «… отличный пример того, как TDD улучшает ваш дизайн».
Кроме того, он заявляет: «В исходном классе эта посторонняя функциональность исчезла, обернута внутри порожденного класса, поэтому дизайн исходного класса проще и лучше соответствует принципу единой ответственности».
Я бы сказал, что перемещаемая функциональность вовсе не является «посторонней». Кроме того, «проще» не является четко определенной: это, безусловно, может быть случай, когда простота класса обратно пропорциональна его размеру, но это не означает, что система простейших классов будет самой простой из возможных систем: если бы это было так, все классы содержали бы только один метод, а система имела бы огромное количество классов; Можно утверждать, что удаление этого иерархического слоя множественных методов внутри классов сделает систему намного более сложной.
Принцип единой ответственности (SRP), кроме того, общеизвестно субъективен и полностью зависит от уровня абстракции наблюдателя. Это вовсе не тот случай, когда удаление метода из класса автоматически улучшает его соответствие SRP. Класс Printer с 10 методами несет единоличную ответственность за печать на уровне абстракции класса. Одним из его методов может быть checkPrinterConnected (), а другим - checkPaper (); на уровне методов это явно отдельные обязанности, но они не предлагают автоматически разбивать класс на последующие классы.
Карл Финишеs, «В порожденном классе извлеченная функциональность является ее смыслом, поэтому она является общедоступной и поэтому тестируемой без модификаций только для тестирования». Важность функциональности (это raison-d'etre-ness не является основанием для уместности его публичности. Основой приемлемости общедоступности функциональности является минимизация интерфейса, предоставляемого клиенту, так что функциональность класса доступна для использования, в то время как независимость клиента от реализации функциональности максимальна. Конечно, если вы перемещаете только один метод в порожденный класс, он должен быть публичным. Однако, если вы перемещаете более одного метода, вы должны сделать эти методы общедоступными, которые необходимы для успешного использования клиентом класса: эти открытые методы могут быть гораздо менее важными, чем некоторые из частных методов, от которых вы хотите защитить свои. клиент. (В любом случае, я не в восторге от этой фразы «Raison-d'etre», поскольку важность метода также не вполне определена.)
Альтернативный подход к предложению Карла зависит от того, насколько велика ваша система для роста. Если его число возрастет до нескольких тысяч, то вы можете рассмотреть возможность создания сценария для копирования исходного кода в новый каталог, изменения всех вхождений с «private» на «public» в этом скопированном источнике и затем записи своего тесты против скопированного источника. Это имеет недостаток времени, необходимого для копирования кода, но дает преимущество сохранения инкапсуляции исходного кода, но делает все методы тестируемыми в скопированной версии.
Ниже приведен скрипт, который я использую для этой цели.
С уважением,
Эд Кирван
! / Bin / Баш
rm -rf code-copy
echo Создание кода-копии ...
MKDIR код-копия
cp -r ../www code-copy /
для меня в find code-copy -name "*php" -follow
; делать
sed -i 's/private/public/g' $i
сделано
php run_tests.php