[JAVA] Développement piloté par les tests avec le langage fonctionnel Elm (Chapitre 5-7)

Ceci est une continuation de l'article précédent (https://qiita.com/ababup1192/items/d6ca1af6efcbac8d550f). La dernière fois, j'ai vérifié la force du type de données d'Elm (en particulier la comparaison équivalente). Et ce contenu? Nous allons jeter un coup d'oeil.

Chapitre 5

Jusqu'à présent, la seule devise que nous pouvions gérer était le dollar américain, mais ajoutons le franc. De plus, il y a des corrections dans la partie signalée dans le commentaire précédent. Si vous écrivez module Dollar exposing (..) '', vous ne pouvez pas réellement réécrire Amount, mais vous pouvez l'obtenir, donc ce n'est pas privé. Si vous écrivez module Dollar exposing (Dollar) '', vous pouvez le rendre privé, mais dans ce cas vous ne pourrez pas écrire un constructeur de valeur comme Dollar 5```. .. Pour éviter cela, vous devez exposer la fonction dite de modèle d'usine `` dollar: Int-> Dollar```. En lisant ce livre, le modèle d'usine apparaîtra dans un chapitre ultérieur, donc j'irai avec un montant public (non réinscriptible) jusqu'à ce point.

Tout d'abord, écrivons uniquement le test. Bien sûr, c'est une erreur de compilation. À ce stade, une simple comparaison de devises est exclue du scénario de test car elle est garantie dans la langue, comme nous l'avons confirmé la dernière fois. Puisque le temps est couvert par le nom, il est utilisé correctement dans les modules Dollar et Franc.

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
            ]
        ]

Comme vous pouvez le voir dans ce livre, c'est très douloureux, mais copions et collons la définition du dollar et implémentons le franc. Un simple remplacement suffit.

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

Puisque le test a réussi, le TODO sera comme suit.

Chapitre 6

Dans les livres de ce chapitre, nous hériterons d'éliminer la duplication du Dollar et du Franc. Il n'y a pas de concept d'héritage direct chez l'orme, mais je pense que c'était un résultat intéressant personnellement pour savoir comment l'exprimer et quel genre d'effet il a.

Pour porter plus précisément la classe Money d'un livre, je pense que la définition est la suivante.

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

Cependant, lors de la reproduction de l'héritage de la POO, je ne pense pas qu'elm prendrait la peine d'écrire le code ci-dessus, alors je l'ai écrit sous la forme de * Union Types * comme suit. En Java, je pense que chaque classe est divisée et chaque définition est décrite. Cependant, dans ce cas, comme vous pouvez le voir à partir des fonctions times et ``amount, il reçoit et retourne des arguments de type``Money, et a un modèle. En branchant avec une correspondance, vous décrirez le traitement pour chaque type ramifié (pour être exact, la valeur). Si vous êtes familier avec Java, vous pouvez ressentir le ** signe désagréable ** de instance de` `` et le branchement par casting. Mais rassurez-vous. Selon le compilateur, les types de branche autres que le type Money lèveront naturellement une erreur, et comme amount peut également être obtenu au moment de la correspondance de modèle, il n'y aura pas de conversion (et l'erreur d'exécution qui l'accompagne). ..

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

Le point que j'ai ressenti le pouvoir d'Elm cette fois est le type Int-> Money-> Money de times```. Si elle est implémentée en Java, la signature devrait ressembler à ceci: En d'autres termes, il est défini dans chaque classe et renvoyé comme chaque type concret. Autrement dit, vous ne pouvez pas éliminer les doublons de times``` à moins que vous ne déplaciez le champ ```amount``` sur le type Money '' et que vous renvoyiez une valeur de type Money ''. Il est. Cette mise en œuvre sera l'histoire du chapitre 10. À l'heure actuelle, en raison des restrictions de type du dollar et du franc, la duplication des temps n'est pas complètement éliminée, mais il est étonnant que la mise en œuvre proche du chapitre 10 ait déjà été achevée en plus de la mise en œuvre du chapitre 6. Je ressens

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

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

Dans la continuité de la dernière fois, la comparaison équivalente est puissante. L'implémentation Java de equals dans le livre ressemble à ceci: Je l'ai jeté de force dans le type Argent '' et je compare les montants. Naturellement, la comparaison entre le dollar et le franc sera réussie. De plus, bien que cela ne soit pas essentiel, si vous ne comparez pas étroitement les types d'instances, vous obtiendrez une erreur d'exécution avec un échec de conversion lorsqu'un type autre que le type Money entre en jeu. Avec la notation type Money = Dollar Amount | Franc Amount '', la comparaison entre Dollar et Franc ne réussira jamais, et un autre type entraînera une erreur de compilation dès que vous le passerez à l'opérateur de comparaison. Je suis très heureux d'être protégé par la moisissure.

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

Enfin, le scénario de test change comme ceci. Il vous suffit de charger le module Money '' , et vous pouvez voir que times``` est généralisé.

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
            ]
        ]

La liste TODO cette fois est la suivante. Plus le contenu progresse, plus la puissance fonctionnelle apparaîtra (tous les éléments avec des lignes d'annulation). En d'autres termes, ** la langue complète automatiquement le test pour confirmer la sécurité et le comportement que vous souhaitez qu'il soit intuitivement **.

Code final complet

Chapitre 7

Je suis désolé. Ce sont des informations supplémentaires. La comparaison entre le dollar américain et le franc est déjà terminée au chapitre 6.

Résumé

Comme mentionné à la fin du chapitre 6, la caractéristique des types fonctionnels est qu'ils ont plus de restrictions que les POO tels que Java et les types procéduraux. Mais cette contrainte n'est en aucun cas une contrainte pour vous priver de votre liberté. En demandant au compilateur de vérifier soigneusement le type, pas la distribution, le degré d'abstraction est augmenté et le branchement peut se dérouler en toute sécurité. De plus, vous n'avez pas à écrire de code redondant ou à tester du code pour cela. Cela vous permet également de vous concentrer sur votre code logique et d'améliorer la qualité de votre application. Si vous n'avez pas encore acheté le livre "Test Driven Development", veuillez l'acheter et le comparer avec Java. Vous remarquerez sûrement le charme d'Elm!

Recommended Posts

Développement piloté par les tests avec le langage fonctionnel Elm (Chapitre 15-16)
Développement piloté par les tests avec le langage fonctionnel Elm (Chapitre 5-7)
Développement piloté par les tests avec le langage fonctionnel Elm