L’encapsulation a bien un but, mais elle peut aussi être mal utilisée ou mal utilisée.
Considérons quelque chose comme l'API Android qui a des classes avec des dizaines (voire des centaines) de champs. Exposer ces champs au consommateur de l'API rend plus difficile la navigation et l'utilisation, mais donne également à l'utilisateur la fausse idée qu'il peut faire ce qu'il veut avec ces champs pouvant entrer en conflit avec la manière dont ils sont censés être utilisés. L'encapsulation est donc excellente dans ce sens pour la maintenabilité, la facilité d'utilisation, la lisibilité et pour éviter les bugs fous.
D'autre part, un type de données POD ou ancien, tel qu'une structure de C / C ++ dans laquelle tous les champs sont publics, peut également être utile. Avoir des getters / setters inutiles comme ceux générés par l'annotation @data à Lombok n'est qu'un moyen de conserver le "modèle d'encapsulation". Une des rares raisons pour lesquelles nous utilisons des getters / setters "inutiles" en Java est que les méthodes fournissent un contrat .
En Java, vous ne pouvez pas avoir de champs dans une interface. Par conséquent, vous utilisez des getters et des setters pour spécifier une propriété commune à tous les implémenteurs de cette interface. Dans des langages plus récents comme Kotlin ou C #, le concept de propriété est défini comme un champ pour lequel vous pouvez déclarer un séparateur et un getter. En fin de compte, les getters / setters inutiles sont plus un héritage avec lequel Java doit vivre, à moins que Oracle y ajoute des propriétés. Kotlin, par exemple, qui est un autre langage JVM développé par JetBrains, a des classes de données qui font comme l’annotation @data à Lombok.
Aussi, voici quelques exemples:
class DataClass
{
private int data;
public int getData() { return data; }
public void setData(int data) { this.data = data; }
}
C'est un mauvais cas d'encapsulation. Le getter et le setter sont effectivement inutiles. L'encapsulation est principalement utilisée car il s'agit du standard dans des langages tels que Java. N'aide en réalité pas, outre le maintien de la cohérence dans la base de code.
class DataClass implements IDataInterface
{
private int data;
@Override public int getData() { return data; }
@Override public void setData(int data) { this.data = data; }
}
C'est un bon exemple d'encapsulation. L'encapsulation est utilisée pour appliquer un contrat, dans ce cas IDataInterface. Le but de l'encapsulation dans cet exemple est de faire en sorte que le consommateur de cette classe utilise les méthodes fournies par l'interface. Bien que le getter et le setter ne fassent rien d'extraordinaire, nous avons maintenant défini un trait commun entre DataClass et d'autres implémenteurs d'IDataInterface. Ainsi, je peux avoir une méthode comme celle-ci:
void doSomethingWithData(IDataInterface data) { data.setData(...); }
Maintenant, quand on parle d’encapsulation, je pense qu’il est important de s’attaquer également au problème de syntaxe. Je vois souvent des gens se plaindre de la syntaxe nécessaire pour appliquer l'encapsulation plutôt que l'encapsulation elle-même. Un exemple qui me vient à l’esprit est celui de Casey Muratori (vous pouvez voir son discours ici ).
Supposons que vous ayez une classe de joueurs qui utilise l’encapsulation et que vous voulez déplacer sa position d’une unité. Le code ressemblerait à ceci:
player.setPosX(player.getPosX() + 1);
Sans encapsulation, cela ressemblerait à ceci:
player.posX++;
Il soutient ici que les encapsulations conduisent à beaucoup plus de dactylographie sans avantages supplémentaires et que cela peut dans de nombreux cas être vrai, mais remarquez quelque chose. L'argument est contraire à la syntaxe, pas à l'encapsulation elle-même. Même dans les langages comme le C qui n’ont pas le concept d’encapsulation, vous verrez souvent des variables dans des structures prexifed ou sufixées par '_' ou 'my' ou autre pour indiquer qu’elles ne doivent pas être utilisées par le consommateur de l’API, comme si elles étaient utilisées. privé.
Le fait est que l'encapsulation peut aider à rendre le code beaucoup plus facile à gérer et à utiliser. Considérez cette classe:
class VerticalList implements ...
{
private int posX;
private int posY;
... //other members
public void setPosition(int posX, int posY)
{
//change position and move all the objects in the list as well
}
}
Si les variables étaient publiques dans cet exemple, le consommateur de cette API serait confus quant à savoir quand utiliser posX et posY et quand utiliser setPosition (). En masquant ces détails, vous aidez le consommateur à mieux utiliser votre API de manière intuitive.
La syntaxe est cependant une limitation dans de nombreuses langues. Cependant, les nouveaux langages offrent des propriétés qui nous donnent la syntaxe intéressante des membres de publice et les avantages de l'encapsulation. Vous trouverez des propriétés en C #, Kotlin, même en C ++ si vous utilisez MSVC. voici un exemple à Kotlin.
class VerticalList: ... {var posX: Int défini (x) {champ = x; ...} var posY: Int set (y) {champ = y; ...}}
Ici, nous avons réalisé la même chose que dans l'exemple Java, mais nous pouvons utiliser posX et posY comme s'il s'agissait de variables publiques. Quand j'essaye de changer leur valeur, le corps du set set () sera exécuté.
Dans Kotlin, par exemple, cela équivaudrait à un Java Bean avec getters, setters, hashcode, equals et toString:
data class DataClass(var data: Int)
Notez que cette syntaxe nous permet de créer un bean Java sur une seule ligne. Vous avez correctement remarqué le problème d’un langage tel que Java lors de l’implémentation de l’encapsulation, mais c’est la faute de Java et non de l’encapsulation elle-même.
Vous avez dit que vous utilisiez @Data de Lombok pour générer des getters et des setters. Notez le nom, @Data. Il est principalement conçu pour être utilisé sur des classes de données qui stockent uniquement des données et doivent être sérialisées et désérialisées. Pensez à quelque chose comme un fichier de sauvegarde d'un jeu. Mais dans d'autres scénarios, comme dans le cas d'un élément d'interface utilisateur, vous souhaitez sans aucun doute définir des paramètres, car modifier la valeur d'une variable risque de ne pas suffire pour obtenir le comportement attendu.
"It will create getters, setters and setting constructors for all private fields."
- La façon dont vous décrivez cet outil, il semble que cela est le maintien de l' encapsulation. (Au moins dans un sens vague, automatisé et un peu anémique.) Alors quel est exactement le problème?