FizzBuzz orienté objet (Java)

introduction

Cet article est l'article du 11ème jour du Calendrier de l'Avent FizzBuzz 2017.

Tout le monde aime Fizz Buzz. Il est également utilisé dans notre entreprise comme première question de formation avant de rejoindre l'entreprise. Quel que soit le langage, il devrait s'agir d'une ligne de base, donc il n'y a pas de problème, mais je me demandais ce qui se passerait si je l'écrivais en orienté objet (POO), alors je l'ai écrit en Java.

Fiche de FizzBuzz

Jetons à nouveau un coup d'œil à FizzBuzz.

Énoncé du problème

Comptez les nombres de 1 à 100,

--Fizz pour les multiples de 3 --Buzz pour les multiples de 5 --FizzBuzz pour les multiples de 3 et 5 --Autre que ça, ce numéro

Est sortie.

Réponse ordinaire

C'est juste une réponse "Java" normale.

public class FizzBuzz {
    public static void main(String[] args) {
        for (int i = 1; i <= 100; i++) {
            if (i % 3 == 0 && i % 5 == 0) {
                System.out.println("FizzBuzz");
            } else if (i % 3 == 0) {
                System.out.println("Fizz");
            } else if (i % 5 == 0) {
                System.out.println("Buzz");
            } else {
                System.out.println(i);
            }
        }
    }
}

Afin de créer ce code orienté objet, nous allons d'abord concevoir la classe.

Conception de classe

Suivez les étapes ci-dessous pour concevoir une classe.

  1. Identification des objets
  2. Examen du modèle
  3. Sélection du nom de la classe

1. Identification des objets

Tout d'abord, identifiez les objets qui apparaissent dans le problème.

  1. Un objet qui "compte les nombres de 1 à 100 et produit le résultat selon les conditions"
  2. Un objet qui "vérifie les multiples de 3 et renvoie Fizz"
  3. Un objet qui "vérifie les multiples de 5 et renvoie Buzz"
  4. Un objet qui "vérifie les multiples de 3 et 5 et renvoie FizzBuzz"

Il n'y a pas de problème particulier car il est simplement résumé par rôle.

2. Examen du modèle

Considérez le modèle requis parmi les objets donnés ci-dessus.

Tout d'abord, "comptez les nombres de 1 à 100 et sortez le résultat selon les conditions". Il a une fonction d'entrée / sortie "d'obtenir une plage de valeurs numériques et de conditions, et de sortir une chaîne de caractères selon les conditions".

Ensuite, concernant 2. ~ 4, on peut dire qu'ils ont la même fonction à l'exception des valeurs numériques et des chaînes de caractères spécifiques. En tant que fonction, il semble qu'il puisse être décomposé en deux fonctions, "vérifier s'il est divisible par le nombre spécifié (vérifier avec et s'il y en a plusieurs)" et "tenir la chaîne de caractères correspondant à la condition".

En résumé, ce serait bien d'avoir les trois modèles suivants.

3. Sélection du nom de la classe

Citons les trois modèles mentionnés ci-dessus. Utilisez le nom tel quel comme nom de classe.

Nom une fonction
Operator Obtenez une plage de nombres et de conditions, et affichez une chaîne de caractères en fonction des conditions
Specification Vérifiez s'il est divisible par le nombre spécifié
Operation Contient la chaîne correspondant à la condition

Des modèles tels que Specification sont introduits dans Domain Driven Development (DDD) dans un modèle appelé ** Specification Pattern **. Maintenant que nous avons les classes nécessaires, nous allons les implémenter.

la mise en oeuvre

Sur la base du modèle conçu, nous le déposerons dans le code Java. (Puisqu'il est placé du côté à utiliser, il est différent de l'ordre du modèle ci-dessus.)

Specification.java


import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

public class Specification {

    private List<Predicate<Integer>> predicateList = new ArrayList<>();

    public Specification(Predicate<Integer> predicate) {
        this.predicateList.add(predicate);
    }

    private Specification(List<Predicate<Integer>> predicateList) {
        this.predicateList = predicateList;
    }

    public Specification and(Predicate<Integer> predicate) {
        List<Predicate<Integer>> results = new ArrayList<>(this.predicateList);
        results.add(predicate);
        return new Specification(results);
    }

    public boolean isSatisfiedBy(Integer number) {
        return this.predicateList.stream().allMatch(p -> p.test(number));
    }

}

Il y a quatre points principaux dans l'implémentation de Specification.java:

Operation.java


public class Operation {

    private Specification specification;
    private String message;

    Operation(Specification specification, String message) {
        this.specification = specification;
        this.message = message;
    }

    public Specification getSpecification() {
        return this.specification;
    }

    public String getMessage() {
        return message;
    }

}

Operator.java


import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;

public class Operator {

    private List<Operation> operationList = new ArrayList<>();

    public void addOperation(Operation operation) {
        this.operationList.add(operation);
    }

    public void run(IntStream range) {
        range.forEach(number -> {
            String message = this.operationList.stream()
                    .filter(operation -> operation.getSpecification().isSatisfiedBy(number))
                    .map(Operation::getMessage)
                    .findFirst()
                    .orElse(String.valueOf(number));
            System.out.println(message);
        });
    }

}

La partie pour vérifier la condition est écrite dans une doublure en utilisant Stream. La partie de .findFirst (). OrElse () doit être remplie pour voir s'il existe une meilleure façon de l'écrire.

J'écrirai également le code pour exécuter FizzBuzz en utilisant la classe ci-dessus.

FizzBuzz.java


import java.util.function.Predicate;
import java.util.stream.IntStream;

public class FizzBuzz {

    public static void main(String[] args) {
        Operator operator = new Operator();

        Predicate<Integer> divisibleBy3 = DivisiblePredicateFactory.divisibleBy(3);
        Predicate<Integer> divisibleBy5 = DivisiblePredicateFactory.divisibleBy(5);

        Operation fizzbuzz = new Operation(new Specification(divisibleBy3).and(divisibleBy5), "FizzBuzz");
        Operation fizz = new Operation(new Specification(divisibleBy3), "Fizz");
        Operation buzz = new Operation(new Specification(divisibleBy5), "Buzz");

        operator.addOperation(fizzbuzz);
        operator.addOperation(fizz);
        operator.addOperation(buzz);

        operator.run(IntStream.rangeClosed(1, 100));
    }

}

DivisiblePredicateFactory.java


import java.util.function.Predicate;

public class DivisiblePredicateFactory {

    public static Predicate<Integer> divisibleBy(Integer divisor) {
        return n -> n % divisor == 0;
    }

}

Si vous regardez FizzBuzz.java, vous pouvez voir que le rôle de chaque classe est clair et que le style d'écriture est lié à l'énoncé du problème. Même s'il existe une spécification supplémentaire telle que "Bar si c'est un multiple de 7", vous pouvez facilement imaginer où éditer. C'est le bon point de la programmation orientée objet.

Résumé

Cette fois, j'ai écrit FizzBuzz d'une manière orientée objet. Même avec un problème aussi simple, il était assez intéressant de réfléchir sérieusement à l'orientation des objets. La prochaine fois, j'écrirai un test.

Le code publié ici est résumé sur Github, donc si vous le souhaitez, essayez de l'exécuter à portée de main et essayez de l'améliorer à nouveau. (Et veuillez tirer la demande.) https://github.com/totto357/OOP-FizzBuzz

Le 12ème jour de demain sera le "FizzBuzz de @ aimof composé uniquement de définitions de fonctions sur une ligne, à l'exclusion des instructions d'exécution"!

prime

Il s'agit d'une implémentation dans le modèle Builder de la classe Operation rejetée. Cela semblait bien de pouvoir exprimer "quand ~~, afficher xx" dans le code, mais je l'ai rejeté car il ne ressemblait pas à Java. Cependant, je vais le laisser car c'est un gros problème.

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class OperationWithBuilder {

    private Specification specification;
    private String message;

    private Operation(Builder builder) {
        this.specification = builder.getSpecification();
        this.message = builder.getMessage();
    }
    
    public static Builder when(Predicate<Integer> predicate) {
        return new Builder(predicate);
    }
    
    @Getter
    static class Builder {
    
        private Specification specification;
        private String message;
        
        public Builder(Predicate<Integer> predicate) {
            this.specification = new Specification(predicate);
        }
        
        public Builder and(Predicate<Integer> predicate) {
            this.specification = this.specification.and(predicate);
            return this;
        }
        
        public Operation print(String message) {
            this.message = message;
            return new Operation(this);
        }
    
    }

}

Lors de l'utilisation

Predicate<Integer> divisibleBy3 = DivisiblePredicateFactory.divisibleBy(3);
Predicate<Integer> divisibleBy5 = DivisiblePredicateFactory.divisibleBy(5);

Operation fizz = Operation.when(divisibleBy3).print("Fizz");
Operation fizzbuzz = Operation.when(divisibleBy3).and(divisibleBy5).print("FizzBuzz");

Recommended Posts

FizzBuzz orienté objet (Java)
[Java] Orienté objet
[Java] Résumé orienté objet_Partie 1
[Java] Syntaxe orientée objet --Constructeur
Notions de base orientées objet (Java)
[Java] Résumé orienté objet_Partie 2
FizzBuzz en Java
[Java] Syntaxe orientée objet --Package
Orienté objet avec Strike Gundam (java)
Résumé orienté objet par les débutants (Java)
Java
Mémorandum des éléments majeurs de Java 3 (orienté objet)
Java
[Java] Syntaxe orientée objet - Méthode / argument de classe
[Java] Syntaxe orientée objet --Classe / champ / méthode / portée
Résumé de la programmation orientée objet utilisant Java
J'ai comparé Java et Ruby FizzBuzz.
Apprendre Java (0)
Étudier Java ―― 3
[Java] tableau
Java protégé
[Java] Annotation
Module [Java]
Étudier Java ―― 9
Java scratch scratch
Astuces Java, astuces
Méthodes Java
Méthode Java
java (constructeur)
Tableau Java
[Java] ArrayDeque
java (remplacement)
java (méthode)
Résumé orienté objet
Journée Java 2018
Chaîne Java
java (tableau)
Programmation orientée objet
Java statique
Sérialisation Java
java débutant 4
JAVA payé
Étudier Java ―― 4
Java (ensemble)
tri shell java
[Java] compareTo
Étudier Java -5
java réfléchissant 获 获 举
java (interface)
Mémorandum Java
Tableau Java
Étudier Java ―― 1
[Java] Array
[Java] Polymorphisme
Étudier Java # 0
Revue Java
framework java
Fonctionnalités Java
[Java] Héritage
FastScanner Java