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