Als Einführung möchte ich an das Zitat von
Onkel Bob erinnern
Sie lesen diesen Artikel aus zwei Gründen. Der erste - Sie sind Programmierer, der zweite - Sie möchten der beste Programmierer sein.
Stellen Sie sich vor, Sie sind in einer Bibliothek und suchen nach Büchern. Wenn die Bibliothek sortiert ist und Kategorien von Büchern enthält, finden Sie schnell die gewünschte. Darüber hinaus wird das coole Innendesign und die Architektur Ihren Aufenthalt in dieser Bibliothek für Sie sehr angenehm machen.
Wie beim Schreiben von Büchern müssen Sie wissen, wie Sie schreiben und Ihren Code organisieren, wenn Sie etwas Großartiges erstellen möchten. Wenn Sie Teammitglieder oder eine andere Person haben, die Ihren (veralteten) Code hat, müssen sie nur die Variablennamen oder Pakete oder Klassen sehen, und sie werden es sofort verstehen. Sie müssen diesen Code nicht "E ** l" sagen und ihn von vorne beginnen.
Was ist ein sauberer Code?

ÜbersetzungLieber Programmierer:
Als ich diesen Code schrieb, wussten nur Gott und ich, wie es funktioniert!
Jetzt weiß nur Gott das!
Bevor Sie versuchen, diese Routine zu optimieren und sie (höchstwahrscheinlich) nicht zum Erfolg führt, erhöhen Sie bitte den Zeitzähler, um den nächsten Entwickler zu warnen
Gesamtstunden: 567
Wie Sie sehen, reicht es nicht aus, die Entwicklung schneller abzuschließen. Wenn sie diesen Code in Zukunft nicht herausfinden können, wird er auch zu einer technischen Schuld.
Ihr Code befindet sich in einem "reinen" Zustand, wenn jedes Mitglied Ihres Teams ihn verstehen kann. Sauberer Code kann von jedem anderen Entwickler als dem ursprünglichen Autor gelesen und verbessert werden. Mit dem Verständnis geht Lesbarkeit, Veränderlichkeit, Erweiterbarkeit und Wartbarkeit einher.
Soll ich mich darum kümmern?
Der Grund, warum Sie sich um die Sauberkeit Ihres Codes kümmern sollten, ist, dass Sie Ihre Gedanken anderen Entwicklern beschreiben. Deshalb sollten Sie darauf achten, dass Ihr Code eleganter, einfacher und lesbarer ist.
Anzeichen von sauberem Code
- Ihr Code sollte elegant sein: Ihr Code sollte Sie zum Lächeln bringen wie eine gut gemachte Spieluhr oder ein gut gestaltetes Auto
- Ihr Code sollte fokussiert sein: Jede Funktion, jede Klasse, jedes Modul implementiert eine Aufgabe, die nicht durch umgebende Details abgelenkt und verschmutzt wird.
- Code enthält keine Duplikate
- Bestehen Sie alle Tests erfolgreich
- Minimierte die Anzahl der Entitäten, Methoden, Klassen usw.
Der Unterschied zwischen einem guten Programmierer und einem Fachmann besteht darin, dass ein professioneller Programmierer versteht, dass die Verständlichkeit von Code von größter Bedeutung ist. Ein Fachmann nutzt diese Fähigkeit, um Code zu schreiben, den jeder versteht - Robert C. Martin
Schreiben Sie die bewussten Namen
Die Auswahl eines guten Namens kann viel Zeit in Anspruch nehmen, spart aber später mehr. Der Name einer Variablen, Funktion oder Klasse sollte alle wichtigen Fragen beantworten. Es sollte Ihnen sagen, warum es existiert, warum es benötigt wird und wie man es benutzt. Wenn der Name einen Kommentar erfordert, gibt der Name seinen Zweck nicht an
Einfaches Beispiel
Klassennamen
Klassen und Objekte müssen Substantive sein, z. B. Benutzerdefiniert, WikiPage, Konto und AddressParser. Vermeiden Sie Wörter wie Manager, Prozessor, Daten oder Info. Denken Sie auch daran, dass der Klassenname kein Verb sein sollte.
Methodennamen
Methodennamen sollten Verben sein, z. B. postPayment, deletePage oder save. Zugriffsmodifikatoren, Prädikate sollten nach ihrem Wert benannt und mit dem Präfix get, set und gemäß dem JavaBean-Standard versehen werden.
Bevor wir fortfahren, machen Sie eine kurze Pause, tanken Sie Kaffee und Kekse.

OK, jetzt kommen wir zu den SOLID-Prinzipien.
Schreiben Sie Code, der den SOLID-Prinzipien entspricht
Diese Prinzipien wurden von Onkel Bob entwickelt. SOLID ist eine Abkürzung, die eine Reihe von Prinzipien beschreibt, die zum Schreiben von gutem Code entwickelt wurden.
Prinzip der Einzelverantwortung (en)
Dies bedeutet, dass jede Klasse nur eine Verantwortung tragen sollte. Es sollte nie mehr als einen Grund geben, eine Klasse zu wechseln. Sie müssen Ihrer Klasse nicht alles hinzufügen, nur weil Sie es können. Teilen Sie große Klassen in kleinere auf und vermeiden Sie Gottesklassen.
Ein Beispiel:
Wir haben einen RecyclerView.Adapter mit Geschäftslogik in 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) } }
Dies macht RecyclerView.Adapter nicht allein verantwortlich, da es Geschäftslogik im onBindViewHolder enthält. Diese Methode ist nur für das Einfügen von Daten in die Ansicht verantwortlich.
Das Prinzip der Offenheit / Schließung (O)
Software-Entitäten müssen zur Erweiterung geöffnet, aber zur Änderung geschlossen sein. Dies bedeutet, dass wenn Sie Klasse A entwickeln und Ihre Kollegen die Funktion innerhalb dieser Klasse ändern möchten. Sie können dies leicht tun, indem sie diese Klasse erweitern, ohne die Klasse selbst zu ändern.
Ein einfaches Beispiel ist die RecyclerView.Adapter-Klasse. Sie können es einfach erweitern und Ihren eigenen Adapter mit nicht standardmäßigem Verhalten erstellen, ohne den RecyclerView.Adapter selbst zu ändern.
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) } }
Das Barbara-Lisk-Substitutionsprinzip (L)
Die Kinderklasse sollte die Elternklasse ergänzen und nicht ändern. Dies bedeutet, dass die Unterklasse die übergeordneten Methoden überschreiben muss, die die Funktionalität dieser übergeordneten Klasse nicht verletzen. Beispielsweise erstellen wir eine Klassenschnittstelle mit einem onClick () - Listener. Anschließend wenden Sie den Listener in MyActivity an und geben ihm eine Toast-Aktion, wenn onClick () aufgerufen wird.
interface ClickListener { fun onClick() } class MyActivity: AppCompatActivity(), ClickListener {
Prinzip der Schnittstellentrennung
Dieses Prinzip besagt, dass der Client nicht von Methoden abhängig sein sollte, die er nicht verwendet.
Dies bedeutet, dass Sie nicht alle Klassen A innerhalb der Klasse B neu definieren müssen, wenn Sie Klasse A schreiben und die Funktionalität einer anderen Klasse B hinzufügen möchten.
Beispiel: In unserer Aktivität müssen wir SearchView.OnQueryTextListener () implementieren, aber wir benötigen nur die onQuerySubmit () -Methode.
mSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener{ override fun onQueryTextSubmit(query: String?): Boolean {
Wie machen wir das? Einfach! Erstellen Sie einfach einen Rückruf und eine Klasse, die SearchView.OnQueryTextListener () erweitert.
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 } }
Und so fügen wir es unserer Ansicht hinzu
val listener = SearchViewQueryTextListener( object : SearchViewQueryTextCallback { override fun onQueryTextSubmit(query: String?) {
Oder verwenden Sie die Erweiterungsfunktion in 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?) {
Prinzip der Abhängigkeitsinversion
Abhängigkeit von Abstraktionen, ohne Abhängigkeit von etwas Bestimmtem.
Die Definition der Umkehrung der Abhängigkeit von Onkel Bob besteht aus zwei Konzepten.
Module der oberen Ebene sollten nicht von Modulen der unteren Ebene abhängen. Beide sollten an Abstraktionen gebunden sein. Abstraktionen sollten nicht von den Details abhängen. Details sollten von Abstraktionen abhängen. Übergeordnete Module, die komplexe Logik implementieren, sollten ohne Änderungen an untergeordneten Modulen leicht wiederverwendbar sein. Dazu müssen Sie eine Abstraktion eingeben, die die Module der oberen und unteren Ebene voneinander trennt.
Ein einfaches Beispiel für dieses MVP-Muster. Sie haben ein Schnittstellenobjekt, mit dem Sie mit bestimmten Klassen kommunizieren können. Was ist gemeint - die UI-Klassen (Aktivität / Fragment) müssen die tatsächliche Implementierung der Präsentationsmethoden nicht kennen. Wenn Sie also Änderungen im Presenter vornehmen, müssen sich UI-Klassen nicht um diese Änderungen kümmern.
Schauen wir uns ein Beispiel an
interface UserActionListener { fun getUserData() } class UserPresenter : UserActionListener() {
Und jetzt zur Aktivität
class UserActivity : AppCompatActivity() {
Auf diese Weise erstellen wir eine Schnittstelle, die die Implementierung des Präsentators abstrahiert, und unsere Ansichtsklasse verwaltet einen Verweis auf das PresenterInterface.