>>1139524На js, например:
function factorial(x) { return x > 1 ? x * factorial(x - 1) : 1 }
Пишу по памяти (могу налажать, но это сорт оф самочеллендж):
Single Responsibility - каждый класс / модуль должен отвечать за одну чоткую (прям как Ероха) задачу (приводит к большему количеству небольших по объёму классов, каждый из которых имеет одну ясно поставленную задачу - так реально проще, анон)
Open Close Principle - каждый класс / модуль должен быть открыт для расширения, но закрыт для изменения (обычно все строго типизированные ЯП его обеспечивают, в качестве анти-примеров можно привести monkey-patching в Ruby или переопределение методов прототипов в JS).
Liskov Substitutability Principle - наследники классов должны иметь возможность использоваться в том же контексте, что их родители (например, если метод принимает некий базовый класс, он не должен валиться, если передать туда его наследника; в качестве сорт оф анти-примера можно привести массивы в .NET которые какбэ выполняют интерфейс IList, но выкидывают исключение при вызове Add)
Interface Segregation - сорт оф интерфейс на сценарий использования (приводит к большому количеству атомарных интерфейсов и если эти интерфейсы используются в качестве параметров методов/конструкторов, на выходе имеем loose coupling)
Dependency Inversion ака
Inversion of Control - паттерн, при котором за разрешение своих зависимостей отвечает не сам класс, а некоторый специальный класс-контейнер. Регистрация этих зависимостей, как правило, выносится в отдельные файлы/модули. В совокупности с loose coupling даёт очень годную систему, которую можно легко расширять и быстро менять.
Пример:
Например, представь, что у тебя есть классы юнитов, использующие некий алгоритм для нахождения пути из точки A в B; при этом у тебя может быть несколько реализаций этого алгоритма, каждая в отдельном классе, принимающем некоторые параметры (ограничивающие область поиска например). Если каждый класс юнита будет создавать (и инициализировать) реализацию конкретного класса поиска пути внутри себя, получается сорт оф сильная зависимость.
class HumanoidUnit
{
private DijkstraAlgorithm _pathFindingAlg;
public HumanoidUnit()
{
_pathFindingAlg = new DijkstraAlgorithm(100, 2, 12 ...)
}
public void MoveTo(Point point)
{
// use alg here
}
}
В чём её проблема?
Во-первых у тебя скорее всего будет несколько типовых алгоритмов конфигураций, и, соответственно, будет повторяться код. Представь, что у тебя изменилась сигнатура конструктора, например (добавилось несколько дополнительных параметров в некоторые алгоритмы). Тебе придётся искать все классы юнитов, использующие этот алгоритм и менять вызов ручками. При добавлении каждого юнита, тебе придётся думать какую реализацию для него использовать и снова инициализировать ручками (вероятность опечатки растёт с каждым добавленным юнитом). Если тебе нужно изменить реализацию алгоритма для некоторых видов юнитов - тебе опять же придётся всё делать ручками.
Альтернативный подход - сделать интерфейс IPathFinderAlgorithm с единственным методом, возвращающим путь (Interface Segregation), сделать так, чтобы конкретные алгоритмы нахождения пути его выполняли (сорт оф Liskov Substitutability Principle). Сделать так, чтобы класс юнита принимал этот интерфейс в конструктор, ничего не зная о самом алгоритме и его конфигурации и регистрировать преконфигурированные алгоритмы для юнитов (Dependency Inversion).
class HumanoidUnit
{
private IPathFinderAlgorithm _pathFinder;
HumanoidUnit(IPathFinderAlgorthim pathFinder)
{
_pathFinder = pathFinder;
}
public void MoveTo(Point point)
{
// use alg here
}
}
DRY aka
Dont Repeat Yourself - отсутствие повторения кода (повторение кода плохо тем, что когда требуется изменить повторяемый участок, его приходится менять в большом количестве, порой, весьма не очевидных мест, что приводит к тяжело отлавливаемым ошибкам). Если видишь код, который повторяется в нескольких местах, его можно вынести в отдельную функцию/метод, например. Есть тулзы которые могут считать эту метрику в твоём коде. Антипаттерн -
WET aka
Write Everything Twice.
WET плохо,
DRY хорошо, как бы тяноненавистнически это бы не звучало.