Je suppose que je ne me tromperai pas si je dis que le plus souvent, les gens posent des questions sur les principes SOLID lors des entretiens. Les technologies, les langages et les frameworks sont différents, mais les principes de codage sont généralement similaires: SOLID, KISS, DRY, YAGNI, GRASP et autres valent la peine d'être connus de tous.
Dans l'industrie moderne, le paradigme de la POO a dominé pendant de nombreuses décennies, et de nombreux développeurs ont l'impression qu'il est le meilleur ou même le pire - le seul. Il y a une excellente vidéo sur ce sujet Pourquoi la programmation fonctionnelle n'est-elle pas la norme? sur le développement des langages / paradigmes et les racines de leur popularité.
SOLID a été décrit à l'origine par Robert Martin pour la POO et est perçu par beaucoup comme se référant uniquement à la POO, même wikipedia nous en parle, voyons si ces principes sont si liés à la POO?
Responsabilité unique
Profitons de la vision d' oncle Bob sur SOLID :
Ce principe a été décrit dans les travaux de Tom DeMarco et Meilir Page-Jones. Ils ont appelé cela la cohésion. Ils ont défini la cohésion comme la relation fonctionnelle des éléments d'un module. Dans ce chapitre, nous allons changer un peu ce sens et relier la cohésion aux forces qui provoquent le changement d'un module ou d'une classe.
Chaque module doit avoir une raison de changement (et ne pas faire du tout une chose, autant de réponses) et comme l'auteur lui-même l'a expliqué dans l'une des vidéos, cela signifie que les changements doivent provenir d'un groupe / rôle de personnes, par exemple, le module ne doit changer que selon demandes d'analyste d'affaires, de concepteur, de spécialiste DBA, d'expert-comptable ou d'avocat.
Veuillez noter que ce principe s'applique à un module, qui en POO est une classe. Il existe des modules dans presque toutes les langues, ce principe ne se limite donc pas à la POO.
Ouvert fermé
SOFTWARE ENTITIES (CLASSES, MODULES, FUNCTIONS, ETC.) SHOULD BE OPEN FOR EXTENSION, BUT CLOSED FOR MODIFICATION
Bertrand Meyer
- , — , ( ) .
( , ). , . map
, filter
, reduce
, . , foldLeft
!
def map(xs: Seq[Int], f: Int => Int) =
xs.foldLeft(Seq.empty) { (acc, x) => acc :+ f(x) }
def filter(xs: Seq[Int], f: Int => Boolean) =
xs.foldLeft(Seq.empty) { (acc, x) => if (f(x)) acc :+ x else acc }
def reduce(xs: Seq[Int], init: Int, f: (Int, Int) => Int) =
xs.foldLeft(init) { (acc, x) => f(acc, x) }
, , — .
Liskov Substitution
If for each objecto1
of typeS
there is an objecto2
of typeT
such that for all programsP
defined in terms ofT
, the behavior ofP
is unchanged wheno1
is substituted foro2
thenS
is a subtype ofT
.
, , "" . , , .
"", , "" . , ! , ( ), :
static <T> T increment(T number) {
if (number instanceof Integer) return (T) (Object) (((Integer) number) + 1);
if (number instanceof Double) return (T) (Object) (((Double) number) + 1);
throw new IllegalArgumentException("Unexpected value "+ number);
}
, T
, , "" (.. ), , — .
, , "" , , . , , ( ), , (ad hoc) . .
Interface Segregation
, , , .
, , "" ! , (type classes), .
Comparable
Java
type class Ord
haskell
( class
— haskell
):
//
class Ord a where
compare :: a -> a -> Ordering
"", , , compare
( Comparable
). .
Dependency Inversion
Depend on abstractions, not on concretions.
Dependency Injection, — , :
int first(ArrayList<Integer> xs) // ArrayList ->
int first(Collection<Integer> xs) // Collection ->
<T> T first(Collection<T> xs) //
: ( ):
def sum[F[_]: Monad](xs: Seq[F[Int]]): F[Int] =
if (xs.isEmpty) 0.pure
else for (head <- xs.head; tail <- all(xs.tail)) yield head + tail
sum[Id](Seq(1, 2, 3)) -> 6
sum[Future](Seq(queryService1(), queryService2())) -> Future(6)
, , .
SOLID , . , SOLID , . , !