[JAVA] [Lesung Memo] Prinzipien des Systemdesigns nützlich im Bereich "Klein und leicht zu verstehen"

(Warum) Warum müssen Sie das Verständnis erleichtern?

Die Kosten für die Lieferung eines Produkts (*) hängen von der Verständlichkeit des Programms ab, was zum Design führt.

(Wie) Wie machst du das?

Die Punkte sind die folgenden fünf.

  1. Die Grundlagen der Code-Organisation sind Namen und Absätze
  2. Organisieren Sie Ihren Code mit kurzen Methoden und kleinen Klassen
  3. Machen Sie es einfach, ein Wertobjekt zu verstehen und zu sichern
  4. Sammeln und organisieren Sie komplexe Logik mit Sammlungsobjekten
  5. Je mehr der Klassenname oder der Methodenname mit dem Geschäftsbegriff übereinstimmt, desto einfacher ist es, die Absicht des Programms zu verstehen, und desto einfacher und sicherer ist es, Änderungen vorzunehmen.

(Was) Speziell?

1. Die Grundlagen der Code-Organisation sind Namen und Absätze

Ein verwirrendes Beispiel.kt


var a = 2000
val b = if (c < 2014) 1.05 else 1.08
a = a * b
a = if (a < 2500) a * 0.8 else a
println("gesamt${a}Es ist ein Kreis.");

Leicht verständliches Beispiel.kt


val basePrice = 2000

val taxRate = if (year < 2014) 1.05 else 1.08
val afterTax = basePrice * taxRate

val result = if (afterTax < 2500) afterTax * 0.8 else afterTax

println("gesamt${result}Es ist ein Kreis.");

Punkt

2. Organisieren Sie Ihren Code mit kurzen Methoden und kleinen Klassen

Dank der obigen Änderungen ist es einfacher, die Methode auszuschneiden. Erstens ist es in derselben Klasse ein Beispiel für das Extrahieren der Verarbeitung in eine Methode.

Leicht verständliches Beispiel (Repost).kt


val basePrice = 2000

val taxRate = if (year < 2014) 1.05 else 1.08
val afterTax = basePrice * taxRate

val result = if (afterTax < 2500) afterTax * 0.8 else afterTax

println("gesamt${result}Es ist ein Kreis.");

Beispiel für das Extrahieren einer Methode.kt


fun main(args: Array<String>) {
    val basePrice = 2000

    val afterTax = getAfterTaxAmount(year, basePrice)

    val result = getDiscountedPrice(afterTax)

    println("gesamt${result}Es ist ein Kreis.");
}

fun getAfterTaxAmount(year: Int, basePrice: Int): Double {
    return basePrice * if (year < 2014) 1.05 else 1.08
}

fun getDiscountedPrice(amount: Int): Int {
    return if (amount < 2500) amount * 0.8 else amount
}

Die Vorteile von Extraktionsverfahren sind wie folgt.

  1. In der Lage sein, sicher Korrekturen vorzunehmen, da zukünftige Änderungen in der Methode eingeschlossen sind.
  2. In der Lage sein, die Absicht zum Code in Form von Methodennamen zu vermitteln.
  3. Der Prozess sollte wiederverwendbar sein.

Das Folgende ist ein Beispiel für das Entfernen von doppeltem Code in verschiedenen Klassen.

User.kt


class User(name: String, prefecture: String) {
    fun isInTokyo(): Boolean {
        return prefecture == "Tokyo"
    }
}

Article.kt


class User(title: String, prefecture: String) {
    fun isInTokyo(): Boolean {
        return prefecture == "Tokyo"
    }
}

Die beiden oben genannten Objekte haben den gleichen Wert wie "Präfektur" und eine Methode, die auf der Grundlage dieses Werts verarbeitet werden kann. Dies ist ein doppelter Code.

In diesem Fall unterscheidet sich die Refactoring-Richtlinie zwischen den folgenden beiden Methoden. Es gibt keine Referenzbeziehung zwischen den beiden Objekten ii. Zwischen zwei Objekten besteht eine Referenzbeziehung

Es gibt keine Referenzbeziehung zwischen den beiden Objekten

Es ist eine gute Idee, eine Klasse namens Präfektur zu erstellen und doppelte Logik hinzuzufügen. Auf diese Weise wird beim Hinzufügen, Ändern oder Löschen von Entscheidungslogik basierend auf "Präfektur" nur die Klasse "Präfektur" geändert. Gleichzeitig mit der einfacheren Behebung ist es weniger wahrscheinlich, dass unerwartete Fehler auftreten, wenn die Korrektur weggelassen wird.

Prefecture.kt


class Prefecture(name: String) {
    fun isInTokyo(): Boolean {
        return name == "Tokyo"
    }
}

Der "Benutzer" und "Artikel" lauten wie folgt. Die isInTokyo-Methode wird durch Delegieren jeder Methode realisiert. Daher gibt es auch nach der Änderung keine Änderung im Client.

User.kt


class User(name: String, prefecture: Prefecture) {
    fun isInTokyo(): Boolean {
        return prefecture.isInTokyo()
    }
}

Article.kt


class User(title: String, prefecture: Prefecture) {
    fun isInTokyo(): Boolean {
        return prefecture.isInTokyo()
    }
}

ii. Zwischen zwei Objekten besteht eine Referenzbeziehung

Angenommen, der Benutzer hat einen Artikel, sieht der Implementierungscode folgendermaßen aus: Stellen Sie sicher, dass Sie die Methode des Objekts aufrufen, das Sie besitzen. (Delegieren.) (Artikelumsetzung bleibt gleich)

User.kt


User(name: String, prefecture: String) {
    private val article: Article
    fun isInTokyo(): Boolean {
        return article.isInTokyo()
    }
}

3. Machen Sie es einfach, ein Wertobjekt zu verstehen und zu sichern

Als extremes Beispiel haben Sie wahrscheinlich Code wie diesen gesehen:

Grunddatentyp.kt


class Item {
    val price: Int
    val quantity: Int
}

Was daran falsch ist, ist, dass im obigen Fall erklärt wird, dass die zulässigen Werte für Preis und Menge -2,1 Milliarden bis +2,1 Milliarden betragen. Generell sollte es eine angemessene Obergrenze für die Preise geben. Sie sollten also eine Money-Klasse definieren, um sie darzustellen, und sie in der Item-Klasse haben. Auf diese Weise können Sie die Prüfung auf abnormale Werte, die bei der Preisverarbeitung erforderlich ist, an die Money-Klasse delegieren, und die Sichtbarkeit des Codes in Item wird deutlich.

Angenommen, Sie haben eine Methode, um den Gesamtkaufpreis zu ermitteln. Darüber hinaus gelten folgende Einschränkungen:

  1. Wenn der Stückpreis- ist, werfen Sie einen Fehler.
  2. Wenn der Stückpreis 10.000 überschreitet, wird ein Fehler ausgegeben.

Grunddatentyp.kt


class Item(price: Int, quantity: Int) {
    private val price: Int
    private val quantity: Int

    init {
        this.price = price
        this.quantity = quantity
    }

    fun calculateTotalAmount(): Int {
        if (price < 0 || price > 100000) throw IllegalArgumentException()

        return price * quantity
    }
}

fun main(args: Array<String>) {
        val price = 10000000
        val item: Item = Item(price, 1)
        item.calculateTotalAmount()    
}

Wenn true, sollte alles, was Sie mit "berechneTotalAmount ()" tun möchten, eine Zeile sein, aber es dauert dreimal so viel. Dies liegt daran, dass wir den Wert überprüfen mussten. Diese Wertprüfung wird an die Money-Klasse delegiert.

ValueObject.kt


class Item(price: Money, quantity: Int) {
    private val price: Money
    private val quantity: Int

    init {
        this.price = price
        this.quantity = quantity
    }

    fun calculateTotalAmount(): Int {
        return price.getPrice() * quantity
    }
}

class Money(price: Int) {
    private val price: Int

    init {
        if (price < 0 || price > 100000) throw IllegalArgumentException()

        this.price = price
    }

    fun getPrice(): Int {
        return price
    }
}

Jetzt passt die Item # berechneTotalAmount in eine Zeile und es gibt keine zusätzliche Verarbeitung, so dass die Aussichten besser sind. Selbst wenn Sie für die Verarbeitung des Objekts verantwortlich sind, ist es für die Money-Klasse logischerweise einfacher, den Betrag zu überprüfen.

4. Sammeln und organisieren Sie komplexe Logik mit Sammlungsobjekten

_ Schreibe morgen! _

Impressionen

Das Schreiben in Kotlin hat viel Zeit in Anspruch genommen. .. .. Ich frage mich, ob es zunächst nicht geholfen werden kann. Wenn es um neue Sprachen und neue Informationen geht, kann dies ziemlich belastend sein, daher werde ich ein angemessenes Gleichgewicht halten.

Recommended Posts

[Lesung Memo] Prinzipien des Systemdesigns nützlich im Bereich "Klein und leicht zu verstehen"
Ich habe viel über "Prinzipien des Systemdesigns, die auf diesem Gebiet nützlich sind" gelernt und sie daher zusammengefasst ~ Kapitel 1 ~
Über "Dependency Injection" und "Inheritance", die leicht zu verstehen sind, wenn man sich zusammen erinnert
In der Abbildung verstandene Java-Klassen und -Instanzen
Notiz, die zum Anmeldebildschirm übergeht, wenn Sie nicht mit devise angemeldet sind
Der Unterschied zwischen der Ruby-Instanzmethode und der Klassenmethode ist leicht zu verstehen.
[Bootstrap] Verwendung von "Grid System" für responsives Webdesign
Java-Referenz zum Verständnis in der Abbildung
[Java] Was tun, wenn sich der in der Datenbank gespeicherte Inhalt und der Name der Aufzählung in der Aufzählung unterscheiden, die die Definition der Datenbank widerspiegelt?