[JAVA] Testgetriebene Entwicklung mit der Funktionssprache Elm (Kapitel 5-7)

Dies ist eine Fortsetzung des vorherigen Artikels (https://qiita.com/ababup1192/items/d6ca1af6efcbac8d550f). Beim letzten Mal habe ich die Stärke des Datentyps von Elm überprüft (insbesondere den entsprechenden Vergleich). Wie wäre es mit diesem Inhalt? Lass uns einen Blick darauf werfen.

Kapitel 5

Bisher war die einzige Währung, mit der wir umgehen konnten, US-Dollar, aber fügen wir Franc hinzu. Darüber hinaus gibt es Korrekturen in dem Teil, auf den im vorherigen Kommentar hingewiesen wurde. Wenn Sie `Modul Dollar Exposing (..)` schreiben, können Sie Amount nicht umschreiben, aber Sie können es erhalten, so dass es nicht privat ist. Wenn Sie das Modul "Dollar Exposure (Dollar)" schreiben, können Sie es privat machen. In diesem Fall können Sie jedoch keinen Wertekonstruktor wie "Dollar 5" schreiben. .. Um dies zu vermeiden, müssen Sie die sogenannte Factory-Pattern-Funktion `` `Dollar: Int-> Dollar``` verfügbar machen. Während ich dieses Buch durchlese, wird das Fabrikmuster in einem späteren Kapitel erscheinen, daher werde ich bis zu diesem Zeitpunkt einen öffentlichen (nicht wiederbeschreibbaren) Betrag verwenden.

Schreiben wir zunächst nur den Test. Natürlich ist es ein Kompilierungsfehler. Zu diesem Zeitpunkt ist ein einfacher Währungsvergleich vom Testfall ausgeschlossen, da er in der Sprache garantiert ist, wie wir letztes Mal bestätigt haben. Da die Zeiten durch den Namen abgedeckt sind, wird sie in den Dollar- und Frankenmodulen ordnungsgemäß verwendet.

tests/Test.elm

all : Test
all =
    describe "Money Test"
        [ describe "Dollar"
            [ "Multiplication1"
                => (Dollar 5 |> Dollar.times 2)
                === Dollar 10
            , "Multiplication2"
                => (Dollar 5 |> Dollar.times 3)
                === Dollar 15
            ]
        , describe "Franc"
            [ "Multiplication1"
                => (Franc 5 |> Franc.times 2)
                === Franc 10
            , "Multiplication2"
                => (Franc 5 |> Franc.times 3)
                === Franc 15
            ]
        ]

Wie Sie in diesem Buch sehen können, ist es sehr schmerzhaft, aber lassen Sie uns die Dollar-Definition kopieren und einfügen und den Franken implementieren. Ein einfacher Austausch reicht aus.

src/Franc.elm

module Franc exposing (Franc(..), times)


type alias Amount =
    Int


type Franc
    = Franc Amount


times : Int -> Franc -> Franc
times multiplier (Franc amount) =
    Franc <| multiplier * amount


amount : Franc -> Amount
amount (Franc amount) =
    amount

Da der Test erfolgreich bestanden wurde, lautet das TODO wie folgt.

Kapitel 6

In den Büchern in diesem Kapitel werden wir erben, um die Verdoppelung von Dollar und Franken zu beseitigen. Es gibt kein Konzept der direkten Vererbung in Ulme, aber ich denke, es war persönlich ein interessantes Ergebnis, wie man es ausdrückt und welche Art von Wirkung es hat.

Um die Money-Klasse eines Buches genauer darzustellen, denke ich, dass die Definition wie folgt lautet.

type Dollar = Dollar Amount
type Franc = Franc Amount
type Money = Dolalr | Franc

Wenn ich jedoch die Vererbung von OOP reproduziere, glaube ich nicht, dass Ulme sich die Mühe machen würde, den obigen Code zu schreiben, also habe ich ihn wie folgt in Form von * Union Types * geschrieben. In Java denke ich, dass jede Klasse geteilt und jede Definition beschrieben wird. In diesem Fall empfängt und gibt es jedoch, wie Sie anhand der Funktionen `times``` und` amount sehen können, Argumente als Typ `` `Money ab und hat ein Muster. Durch Verzweigen mit einer Übereinstimmung beschreiben Sie die Verarbeitung für jeden verzweigten Typ (um genau zu sein den Wert). Wenn Sie mit Java vertraut sind, können Sie das ** unangenehme Zeichen ** der `Instanz von `und der Verzweigung durch Casting spüren. Aber seien Sie versichert. Abhängig vom Compiler werfen andere Verzweigungstypen als der Geldtyp natürlich einen Fehler aus, und da zum Zeitpunkt des Mustervergleichs auch "Betrag" erfasst werden kann, erfolgt keine Umwandlung (und der damit verbundene Laufzeitfehler). ..

src/Money.elm

type alias Amount =
    Int


type Money
    = Dollar Amount
    | Franc Amount


times : Int -> Money -> Money
times multiplier money =
    case money of
        Dollar amount ->
            Dollar <| multiplier * amount

        Franc amount ->
            Franc <| multiplier * amount


amount : Money -> Amount
amount money =
    case money of
        Dollar amount ->
            amount

        Franc amount ->
            amount

Was ich diesmal als die Kraft von Elm empfunden habe, ist der Typ `times``` Typ` Int-> Money-> Money```. Bei Implementierung in Java sollte die Signatur folgendermaßen aussehen: Mit anderen Worten, es wird in jeder Klasse definiert und als jeder konkrete Typ zurückgegeben. Das heißt, Sie können Duplikate von "Zeiten" nur entfernen, wenn Sie das Feld "Betrag" in "Geld" verschieben und einen Wert als "Geld" zurückgeben. Es ist. Diese Implementierung wird die Geschichte von Kapitel 10 sein. Gegenwärtig wird aufgrund der Typbeschränkungen von Dollar und Franken die Verdoppelung der Zeiten nicht vollständig beseitigt, aber es ist erstaunlich, dass die Implementierung in der Nähe von Kapitel 10 zusätzlich zur Implementierung von Kapitel 6 bereits abgeschlossen wurde. ich fühle

// Dollar.java
Dollar times(int multiplier);

// Franc.java
Franc times(int multiplier);

Nach dem letzten Mal ist der entsprechende Vergleich leistungsstark. Die Java-Implementierung von `equals``` im Buch sieht folgendermaßen aus: Ich habe es gewaltsam auf den Typ "Geld" umgestellt und die Beträge verglichen. Natürlich wird der Vergleich zwischen Dollar und Franken erfolgreich sein. Auch wenn dies nicht unbedingt erforderlich ist, wird ein Laufzeitfehler mit einem Umwandlungsfehler angezeigt, wenn ein anderer Typ als der Money-Typ eingeht, wenn Sie die Instanztypen nicht genau vergleichen. Mit der Notation `type Money = Dollar Amount | Franc Amount``` wird der Vergleich zwischen Dollar und Franc niemals erfolgreich sein, und ein anderer Typ führt zu einem Kompilierungsfehler, sobald Sie ihn an den Vergleichsoperator übergeben. Ich bin sehr glücklich, durch den Schimmel geschützt zu sein.

// Money.java
public boolean equals(Object object) {
    Money money = (Money) object;
    return amount == money.amount;
}

Schließlich ändert sich der Testfall so. Sie müssen nur das `Money Modul laden, und Sie können sehen, dass `` times``` verallgemeinert ist.

module Tests exposing (..)

import Test exposing (..)
import TestExp exposing (..)


-- Test target modules

import Money exposing (..)


all : Test
all =
    describe "Money Test"
        [ describe "Dollar"
            [ "Multiplication1"
                => (Dollar 5 |> times 2)
                === Dollar 10
            , "Multiplication2"
                => (Dollar 5 |> times 3)
                === Dollar 15
            ]
        , describe "Franc"
            [ "Multiplication1"
                => (Franc 5 |> times 2)
                === Franc 10
            , "Multiplication2"
                => (Franc 5 |> times 3)
                === Franc 15
            ]
        ]

Die TODO-Liste lautet diesmal wie folgt. Mit fortschreitendem Inhalt manifestiert sich die Funktionskraft (alle Elemente mit Stornierungszeilen). Mit anderen Worten, ** die Sprache ergänzt den Test automatisch, um die Sicherheit und das Verhalten zu bestätigen, das Sie intuitiv wünschen **.

Vollständiger endgültiger Code

Kapitel 7

Es tut mir Leid. Es sind zusätzliche Informationen. Der Vergleich zwischen US-Dollar und Franken ist bereits ab Kapitel 6 beendet.

Zusammenfassung

Wie am Ende von Kapitel 6 erwähnt, besteht das Merkmal von Funktionstypen darin, dass sie mehr Einschränkungen aufweisen als OOPs wie Java und Prozedurtypen. Aber diese Einschränkung ist keineswegs eine Einschränkung, um Sie Ihrer Freiheit zu berauben. Indem der Compiler den Typ und nicht die Umwandlung sorgfältig überprüft, wird der Abstraktionsgrad erhöht und die Verzweigung kann sicher fortgesetzt werden. Außerdem müssen Sie keinen redundanten Code oder Testcode dafür schreiben. Auf diese Weise können Sie sich auch auf Ihren Logikcode konzentrieren und die Qualität Ihrer Anwendung verbessern. Wenn Sie das Buch "Test Driven Development" noch nicht gekauft haben, kaufen Sie es bitte und vergleichen Sie es mit Java. Sie werden sicherlich den Charme von Elm bemerken!

Recommended Posts

Testgetriebene Entwicklung mit der Funktionssprache Elm (Kapitel 15-16)
Testgetriebene Entwicklung mit der Funktionssprache Elm (Kapitel 5-7)
Testgetriebene Entwicklung mit der Funktionssprache Elm