La loi de Déméter (que j'ai mis en lien plus haut) nous dit que l'on ne doit dialoguer qu'avec 4 catégories d'objets : soi-même, nos composants, les objets qu'on reçoit en paramètre, les objets que l'on crée.
La conséquence de la loi en question est que l'on ne doit rien supposer à propos de la composition des objets autre que soi-même, à savoir que l'on ne doit pas accéder aux composants d'un autre objet (bémol : voir plus loin). Donc évidemment, de ce point de vue les setters et les getters violent complètement ce principe puisqu'on accède explicitement à des champs définis dans l'objet (les setters étant encore pire parce qu'ils font de la modification intrusive).
L'autre élément gênant dans la notion de getters et de setters est que le DIP (Dependency Inversion Principle) nous dit que l'on doit dépendre des abstractions et pas des implémentations. Si on a des getters et des setters sur les attributs de nos classes, on est précisément dans le cas où l'on dépend de l'implémentation de la classe (on dépend de ses attributs).
Les classes sont des fournisseurs de services, pas de vulgaires supports de stockage avec des noms (type structs publiques en C, pour un fournisseur de services en C, on cachera généralement la struct dans un header et l'on donnera une API pour manipuler l'élément en question). Quel service rend une classe qui se contente de faire des get et des set sur des champs internes ? Aucun, le getter ne fait que nous donner une info qui ne nécessite pas de calcul et le setter peut éventuellement nous permettre d'implémenter un contrôle à l'entrée, qui est un contrôle de pré-condition (assert en C et en C++) et qui doit donc disparaître en release : le setter n'a rien apporté d'autre qu'un contrôle que le contrat du type est respecté(*).
Le bémol sur la loi de Déméter c'est principalement deux notions. D'abord l'idée que certain conteneur ont justement pour but de fournir du stockage comme par exemple les tableaux, les tables de hash, les listes … Mais d'une part, ils n'exposent rien de leur implémentation (on ne peut pas accéder à leurs champs en modification ni briser leur invariant, juste aux objets qu'on leur a confié) et d'autre part leur service est justement de dire "je fournis un accès indexé à des objets" ou "je fournis un accès séquentiel à un ensemble d'éléments", etc ....
L'autre bémol est les types qui sont des données. Par exemple, un vecteur à trois composantes, ben c'est juste un vecteur, il y a rien à faire. Cependant, faire un accès par getter/setter pour leurs champs est complètement idiot : on met x, y et z publics et basta.
(*) Et le contrôle de respect du contrat n'est pas un service que doit fournir la classe. Le contrat est quelque chose que doit respecter l'utilisateur de la classe.