EDIT: J'ai répondu à cette question car il y a beaucoup de gens qui apprennent la programmation qui le demandent, et la plupart des réponses sont très compétentes techniquement, mais elles ne sont pas aussi faciles à comprendre si vous êtes un débutant. Nous étions tous des débutants, alors j'ai pensé essayer une réponse plus amicale aux débutants.
Les deux principaux sont le polymorphisme et la validation. Même si ce n'est qu'une stupide structure de données.
Disons que nous avons cette classe simple:
public class Bottle {
public int amountOfWaterMl;
public int capacityMl;
}
Une classe très simple qui contient la quantité de liquide qu'il contient et sa capacité (en millilitres).
Que se passe-t-il quand je le fais:
Bottle bot = new Bottle();
bot.amountOfWaterMl = 1500;
bot.capacityMl = 1000;
Eh bien, vous ne vous attendriez pas à ce que cela fonctionne, non? Vous voulez qu'il y ait une sorte de contrôle de santé mentale. Et pire, que se passe-t-il si je n'ai jamais spécifié la capacité maximale? Oh mon cher, nous avons un problème.
Mais il y a aussi un autre problème. Et si les bouteilles n'étaient qu'un type de récipient? Et si nous avions plusieurs conteneurs, tous avec des capacités et des quantités de liquide remplies? Si nous pouvions simplement créer une interface, nous pourrions laisser le reste de notre programme accepter cette interface, et les bouteilles, les jerrycans et toutes sortes de choses fonctionneraient de manière interchangeable. Ce ne serait pas mieux? Comme les interfaces demandent des méthodes, c'est aussi une bonne chose.
Nous finirions avec quelque chose comme:
public interface LiquidContainer {
public int getAmountMl();
public void setAmountMl(int amountMl);
public int getCapacityMl();
}
Génial! Et maintenant, nous changeons simplement la bouteille en ceci:
public class Bottle extends LiquidContainer {
private int capacityMl;
private int amountFilledMl;
public Bottle(int capacityMl, int amountFilledMl) {
this.capacityMl = capacityMl;
this.amountFilledMl = amountFilledMl;
checkNotOverFlow();
}
public int getAmountMl() {
return amountFilledMl;
}
public void setAmountMl(int amountMl) {
this.amountFilled = amountMl;
checkNotOverFlow();
}
public int getCapacityMl() {
return capacityMl;
}
private void checkNotOverFlow() {
if(amountOfWaterMl > capacityMl) {
throw new BottleOverflowException();
}
}
Je laisse la définition de la BottleOverflowException comme un exercice au lecteur.
Maintenant, remarquez à quel point c'est plus robuste. Nous pouvons traiter tout type de conteneur dans notre code maintenant en acceptant LiquidContainer au lieu de Bottle. Et la façon dont ces bouteilles traitent ce genre de choses peut différer. Vous pouvez avoir des bouteilles qui écrivent leur état sur le disque lorsqu'il change, ou des bouteilles qui enregistrent sur des bases de données SQL ou GNU sait quoi d'autre.
Et tout cela peut avoir différentes façons de gérer diverses whoopsies. La bouteille vérifie simplement et si elle déborde, elle lance une RuntimeException. Mais ce n'est peut-être pas la bonne chose à faire. (Il y a une discussion utile à avoir sur le traitement des erreurs, mais je le maintiens très simple ici exprès. Les personnes dans les commentaires vont probablement souligner les défauts de cette approche simpliste.;))
Et oui, il semble que nous passions d'une idée très simple à des réponses bien meilleures rapidement.
Veuillez également noter que vous ne pouvez pas modifier la capacité d'une bouteille. Il est maintenant gravé dans la pierre. Vous pouvez le faire avec un int en le déclarant final. Mais s'il s'agissait d'une liste, vous pouvez la vider, y ajouter de nouvelles choses, etc. Vous ne pouvez pas limiter l'accès à toucher les entrailles.
Il y a aussi la troisième chose que tout le monde n'a pas abordée: les getters et les setters utilisent des appels de méthode. Cela signifie qu'ils ressemblent à des méthodes normales partout ailleurs. Au lieu d'avoir une syntaxe spécifique bizarre pour les DTO et autres choses, vous avez la même chose partout.