Lors de la transformation du code Java en code Ceylan, je rencontre parfois des constructeurs de classe Java qui confondent la vérification et l'initialisation. Utilisons un exemple de code simple mais artificiel pour illustrer ce que je veux expliquer.
Un mauvais code
Considérez la classe Java suivante. (Mec, n'écrivez pas un tel code à la maison)
Période de classe publique {Date finale privée StartDate; Date finale privée Enddate; // Renvoie NULL si la chaîne donnée // ne représente pas une date valide Date privée PARSEDATE (Date de chaîne) {...} Période publique (String start, String end) {startDate = parsedate (start); enddate = parsedate (end); } public boolean isvalid () {return startDate! = null && enddate! = null; } Public Date getStartDate () {if (startDate == null) lancer un nouveau illégalStateException (); return startDate; } Public Date getEndDate () {if (endDate == null) lancer un nouveau illégalStateException (); Retour EndDate; }}Hé, je l'ai déjà prévenu, c'est artificiel. Cependant, il n'est pas rare de trouver quelque chose comme ça dans le code Java réel.
Le problème ici est que même si la vérification des paramètres d'entrée (dans la méthode cachée parsedate ()) échoue, nous obtiendrons toujours une instance de période. Mais la période que nous obtenons n'est pas un état "valide". À strictement parler, qu'est-ce que je veux dire?
Eh bien, si un objet ne peut pas répondre de manière significative à une opération publique, je dirais que c'est dans un état non valide. Dans cet exemple, getStartDate () et getEndDate () lancent une exception illégalStateException, qui est un cas qui ne pense pas être "significatif".
En regardant cet exemple en revanche, lors de la conception de la période, nous n'avons pas réussi à taper la sécurité ici. Les exceptions non contrôlées représentent une «mince-end» dans le système de type. Par conséquent, une meilleure conception de la période sécurisée serait une non-utilisation d'exceptions non contrôlées - dans cet exemple, illégalstateException n'est pas lancée.
(En fait, dans le code réel, je suis plus susceptible de rencontrer une méthode getStartDate () qui ne vérifie pas NULL, après cette ligne de code, il entraînera une exception NullPointerException, ce qui est encore pire.)
Nous pouvons facilement convertir la classe de période ci-dessus en une classe de forme de Ceylan:
Période de classe partagée (String start, string end) {// renvoie null si la chaîne donnée // ne représente pas une date de date valide? parsedate (date de chaîne) => ...; valeur mayBestartDate = parsedate (start); valeur peut-êtrendDate = parsedate (end); partagé booléen valide => MaybestartDate existe && peut-être que laDate existe; Date partagée startDate {assert (existe MayBestartDate); retour MayBestartDate; } Date partagée EndDate {Assert (existe MayBestartDate); retour MayBestartDate; } Date partagée EndDate {Assert (existant peut-êtrendDate); retour peut-êtrendDate; }}Bien sûr, ce code rencontrera également les mêmes problèmes que le code Java d'origine. Deux symboles d'affirmation nous ont crié, il y avait un problème dans la sécurité du type du code.
Améliorer le code Java
Comment améliorer ce code en Java? Eh bien, voici un exemple des exceptions vérifiées critiquées de Java qui sont très raisonnables à résoudre! Nous pouvons modifier légèrement la période pour lancer une exception vérifiée de son constructeur:
Période de classe publique {Date finale privée StartDate; Date finale privée Enddate; // lance si la chaîne donnée // ne représente pas une date de date valide Private Parsedate (Date de chaîne) lève DateFormatexception {...} Public Pério (String start, String end) lève DateFormatexception {startDate = parsedate (start); enddate = parsedate (end); } Public Date getStartDate () {return startDate; } Public Date GetEndDate () {return EndDate; }}Maintenant, avec cette solution, nous n'obtiendrons pas de période dans un état non valide. Le code qui instancie la période sera géré par le compilateur pour gérer les entrées non valides, qui captera une exception DateFormatexception.
essayez {période p = nouvelle période (début, fin); ...} catch (datexception dfe) {...}Il s'agit d'une utilisation agréable, parfaite et correcte des exceptions vérifiées, et malheureusement je vois rarement le code Java en utilisant des exceptions vérifiées comme celle ci-dessus.
Améliorer le code de Ceylan
Alors qu'en est-il de Ceylan? Ceylan n'a pas d'exceptions vérifiées, nous devons donc trouver une solution différente. En règle générale, dans une situation où Java appelle une fonction et lance une exception vérifiée, Ceylan appelle la fonction et renvoie un type d'union. Parce que, l'initialisation d'une classe ne renvoie aucun type, sauf la classe elle-même, nous devons extraire une logique d'initialisation / vérification mixte pour en faire une fonction d'usine.
// Renvoie DateFormaterror si la chaîne donnée // ne représente pas une date valide | DateFormaterror PARSEDATE (String Date) => ... if (est dateFormaterror startDate) {return startDate; } valeur enddate = parsedate (end); if (est dateFormaterror enddate) {return endDate; } Période de retour (startDate, enddate);} Période de classe partagée (startDate, enddate) {Shared Date startDate; Date partagée Enddate;}Selon le système de type, l'appelant est obligé de gérer le DateFormaterror:
valeur p = parseperiod (start, end); if (est dateformaterror p) {...} else {...}Ou, si nous ne nous soucions pas du problème réel avec un format de date donné (ce qui est possible, en supposant que le code d'initialisation sur lequel nous travaillons manque ces informations), nous pouvons utiliser NULL au lieu de DateFormaterror:
// Renvoie NULL si la chaîne donnée // ne représente pas une date valide? parsedate (date de chaîne) => ...; période partagée? parseperiod (String start, string end) => if (existant startDate = parsedate (start), existant endDate = parsedate (end)) puis période (startDate, enddate) else null; partage class période (startDate, enddate) {partage date startDate; Date partagée Enddate;}L'approche de l'utilisation des fonctions d'usine est pour le moins excellente, car elle a généralement une meilleure isolement entre la logique de validation et l'initialisation des objets. Ceci est particulièrement utile à Ceylan, où le compilateur ajoute des restrictions très strictes à la logique d'initialisation de l'objet pour s'assurer que toutes les zones de l'objet ne sont affectées qu'une seule fois.
Ce qui précède est tout le contenu de cet article. J'espère que cela sera utile à l'apprentissage de tous et j'espère que tout le monde soutiendra davantage Wulin.com.