En guise d'introduction, je voudrais rappeler la citation de l'
oncle BobVous lisez cet article pour deux raisons. Le premier - vous êtes programmeur, le second - vous voulez être le meilleur programmeur.
Imaginez que vous êtes dans une bibliothèque et que vous cherchez des livres. Si la bibliothèque est triée, a des catégories de livres, vous trouverez rapidement celui dont vous avez besoin. De plus, la décoration intérieure et l'architecture fraîches rendront votre séjour dans cette bibliothèque très confortable pour vous.
Comme pour l'écriture de livres, si vous voulez créer quelque chose de génial, vous devez savoir comment écrire et organiser votre code. Si vous avez des membres de l'équipe ou quelqu'un d'autre qui a votre code (obsolète), ils ont juste besoin de voir les noms de variables ou les packages ou les classes, et ils comprendront immédiatement. Ils n'ont pas besoin de dire «E ** l» dans ce code et de le recommencer à zéro.
Qu'est-ce qu'un code propre?

La traductionCher programmeur:
Quand j'ai écrit ce code, seul Dieu et moi savions comment cela fonctionne!
Maintenant, seul Dieu le sait!
Avant d'essayer d'optimiser cette routine et cela ne mènera pas au succès (le plus probable), veuillez augmenter le compteur de temps pour avertir le prochain développeur
Nombre total d'heures passées: 567
Comme vous pouvez le voir, il ne suffit pas de terminer le développement plus rapidement. Si à l'avenir ils ne peuvent pas comprendre ce code, il deviendra également une dette technique.
Votre code est dans un état «pur» si chaque membre de votre équipe peut le comprendre. Le code propre peut être lu et amélioré par tout développeur autre que l'auteur d'origine. La compréhension s'accompagne de lisibilité, de mutabilité, d'extensibilité et de maintenabilité.
Dois-je m'en occuper?
La raison pour laquelle vous devez vous soucier de la propreté de votre code est que vous décrivez vos pensées à d'autres développeurs. C'est pourquoi vous devez vous assurer que votre code est plus élégant, simple et lisible.
Signes de code propre
- Votre code doit être élégant: votre code doit vous faire sourire comme une boîte à musique bien faite ou une voiture bien conçue
- Votre code doit être concentré: chaque fonction, chaque classe, chaque module implémente une tâche, qui ne reste pas du tout distraite et non polluée par les détails environnants.
- Le code ne contient pas de doublons
- Réussir tous les tests avec succès
- Réduction du nombre d'entités, de méthodes, de classes, etc.
La différence entre un bon programmeur et un professionnel est qu'un programmeur professionnel comprend que la compréhensibilité du code est primordiale. Un professionnel utilise ce pouvoir pour écrire du code que tout le monde comprend - Robert C. Martin
Écrivez les noms conscients
Choisir un bon nom peut prendre beaucoup de temps, mais cela économisera plus tard. Le nom d'une variable, d'une fonction, d'une classe doit répondre à toutes les questions importantes. Il devrait vous expliquer pourquoi il existe, pourquoi il est nécessaire et comment l'utiliser. Si le nom nécessite un commentaire, le nom ne révèle pas son but
Exemple simple
Noms de classe
Les classes et les objets doivent être des noms, tels que Custom, WikiPage, Account et AddressParser. Évitez les mots comme Manager, Processor, Data ou Info. N'oubliez pas non plus que le nom de la classe ne doit pas être un verbe.
Noms des méthodes
Les noms de méthode doivent être des verbes, par exemple postPayment, deletePage ou save. Les modificateurs d'accès, les prédicats doivent être nommés par leur valeur et avec le préfixe get, défini et selon la norme JavaBean.
Avant de continuer, faites une petite pause, faites le plein de café et de biscuits.

OK, passons maintenant aux principes SOLIDES.
Écrire du code adhérant aux principes SOLID
Ces principes ont été développés par Uncle Bob, SOLID est une abréviation qui décrit un ensemble de principes conçus pour écrire du bon code.
Principe (s) de responsabilité unique
Cela signifie que chaque classe ne devrait avoir qu'une seule responsabilité. Il ne devrait jamais y avoir plus d'une raison pour changer une classe. Pas besoin de tout ajouter à votre classe, simplement parce que vous pouvez le faire. Divisez les grandes classes en plus petites et évitez les classes divines.
Un exemple:
Nous avons un RecyclerView.Adapter avec une logique métier à l'intérieur de onBindViewHolder
class MyAdapter(val friendList: List<FriendListData.Friend>) : RecyclerView.Adapter<CountryAdapter.MyViewHolder>() { inner class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { var name: TextView = view.findViewById(R.id.text1) var popText: TextView = view.findViewById(R.id.text2) } override fun onBindViewHolder(holder: MyViewHolder, position: Int) { val friend = friendList[position] val status = if(friend.maritalStatus == "Married") { "Sold out" } else { "Available" } holder.name.text = friend.name holder.popText.text = friend.email holder.status.text = status } override fun getItemCount(): Int { return friendList.size } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.item_friendlist, parent, false) return MyViewHolder(view) } }
Cela rend RecyclerView.Adapter non seulement responsable car il contient la logique métier à l'intérieur de onBindViewHolder. Cette méthode est uniquement responsable de l'insertion de données dans la vue.
Le principe d'ouverture / fermeture (O)
Les entités logicielles doivent être ouvertes pour l'expansion, mais fermées pour la modification. Cela signifie que si vous développez la classe A et vos collègues voudront changer la fonction à l'intérieur de cette classe. Ils peuvent facilement le faire en développant cette classe sans changer la classe elle-même.
Un exemple simple est la classe RecyclerView.Adapter. Vous pouvez facilement le développer et créer votre propre adaptateur avec un comportement non standard sans modifier le RecyclerView.Adapter lui-même.
class FriendListAdapter(val friendList: List<FriendListData.Friend>) : RecyclerView.Adapter<CountryAdapter.MyViewHolder>() { inner class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { var name: TextView = view.findViewById(R.id.text1) var popText: TextView = view.findViewById(R.id.text2) } override fun onBindViewHolder(holder: MyViewHolder, position: Int) { val friend = friendList[position] holder.name.text = friend.name holder.popText.text = friend.email } override fun getItemCount(): Int { return friendList.size } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.item_friendlist, parent, false) return MyViewHolder(view) } }
Le principe de substitution de Barbara Lisk (L)
La classe enfant doit compléter le parent et ne pas la modifier. Cela signifie que la sous-classe doit remplacer les méthodes parentes qui ne violent pas les fonctionnalités de cette classe parente. Par exemple, nous créons une interface de classe qui a un écouteur onClick () et ensuite vous appliquez l'écouteur dans MyActivity et lui donnez une action Toast lorsque onClick () est appelé.
interface ClickListener { fun onClick() } class MyActivity: AppCompatActivity(), ClickListener {
Principe de séparation des interfaces
Ce principe stipule que le client ne doit pas dépendre de méthodes qu'il n'utilise pas.
Cela signifie que si vous voulez écrire la classe A et y ajouter la fonctionnalité d'une autre classe B. Il n'est pas nécessaire de redéfinir toutes les classes A à l'intérieur de la classe B.
Exemple: dans notre activité, nous devons implémenter SearchView.OnQueryTextListener (), mais nous n'avons besoin que de la méthode onQuerySubmit ().
mSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener{ override fun onQueryTextSubmit(query: String?): Boolean {
Comment fait-on cela? C'est facile! Créez simplement un rappel et une classe étendant SearchView.OnQueryTextListener ()
interface SearchViewQueryTextCallback { fun onQueryTextSubmit(query: String?) } class SearchViewQueryTextListener(val callback: SearchViewQueryTextCallback): SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { callback.onQueryTextSubmit(query) return true } override fun onQueryTextChange(query: String?): Boolean { return false } }
Et donc nous l'ajoutons à notre vue
val listener = SearchViewQueryTextListener( object : SearchViewQueryTextCallback { override fun onQueryTextSubmit(query: String?) {
Ou alors en utilisant la fonction d'extension dans Kotlin
interface SearchViewQueryTextCallback { fun onQueryTextSubmit(query: String?) } fun SearchView.setupQueryTextSubmit (callback: SearchViewQueryTextCallback) { setOnQueryTextListener(object : SearchView.OnQueryTextListener{ override fun onQueryTextSubmit(query: String?): Boolean { callback.onQueryTextSubmit(query) return true } override fun onQueryTextChange(query: String?): Boolean { return false } }) }
val listener = object : SearchViewQueryTextCallback { override fun onQueryTextSubmit(query: String?) {
Principe d'inversion de dépendance
Dépendance à l'égard des abstractions, sans dépendance à quelque chose de spécifique.
La définition de l'inversion de la dépendance à l'égard de l'oncle Bob se compose de deux concepts.
Les modules de niveau supérieur ne doivent pas dépendre de modules de niveau inférieur. Les deux doivent être liés à des abstractions. Les abstractions ne devraient pas dépendre des détails. Les détails doivent dépendre des abstractions. Les modules de haut niveau qui implémentent une logique complexe devraient être facilement réutilisables sans modification des modules de niveau inférieur. Pour ce faire, vous devez saisir une abstraction qui sépare les modules des niveaux supérieur et inférieur les uns des autres.
Un exemple simple de ce modèle MVP. Vous disposez d'un objet d'interface qui vous aide à communiquer avec des classes spécifiques. Ce que cela signifie - les classes d'interface utilisateur (activité / fragment) n'ont pas besoin de connaître la mise en œuvre réelle des méthodes du présentateur. Ainsi, si vous apportez des modifications à l'intérieur du présentateur, les classes d'interface utilisateur n'ont pas à se soucier de ces modifications.
Jetons un coup d'oeil à un exemple
interface UserActionListener { fun getUserData() } class UserPresenter : UserActionListener() {
Et maintenant sur l'activité
class UserActivity : AppCompatActivity() {
De cette façon, nous créons une interface qui résume l'implémentation du présentateur, et notre classe view conserve une référence à PresenterInterface.