Objektorientiertes FizzBuzz (Java)

Einführung

Dieser Artikel ist der Artikel zum 11. Tag von FizzBuzz Advent Calender 2017.

Jeder liebt Fizz Buzz. Es wird in unserem Unternehmen auch als erste Frage der Schulung vor dem Eintritt in das Unternehmen verwendet. Egal um welche Sprache es sich handelt, es sollte ein einfacher Einzeiler sein, es gibt also kein Problem, aber ich habe mich gefragt, was passieren würde, wenn ich es objektorientiert (OOP) schreibe, also habe ich es in Java geschrieben.

Bewertung von FizzBuzz

Werfen wir noch einmal einen kurzen Blick auf FizzBuzz.

Problemstellung

Zähle die Zahlen von 1 bis 100,

Wird ausgegeben.

Gewöhnliche Antwort

Es ist nur eine normale Java-Antwort.

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);
            }
        }
    }
}

Um diesen objektorientierten Code zu erstellen, entwerfen wir zuerst die Klasse.

Klassendesign

Führen Sie die folgenden Schritte aus, um eine Klasse zu entwerfen.

  1. Objekte identifizieren
  2. Untersuchen des Modells
  3. Auswahl des Klassennamens

1. Objekte identifizieren

Identifizieren Sie zunächst die Objekte, die im Problem auftreten.

  1. Ein Objekt, das "Zahlen von 1 bis 100 zählt und das Ergebnis gemäß den Bedingungen ausgibt"
  2. Ein Objekt, das "nach Vielfachen von 3 sucht und Fizz zurückgibt"
  3. Ein Objekt, das "nach Vielfachen von 5 sucht und Buzz zurückgibt"
  4. Ein Objekt, das "nach Vielfachen von 3 und 5 sucht und FizzBuzz zurückgibt"

Es gibt kein besonderes Problem, da es nur nach Rollen zusammengefasst wird.

2. Untersuchen des Modells

Betrachten Sie das erforderliche Modell aus den oben angegebenen Objekten.

Zunächst "zählen Sie die Zahlen von 1 bis 100 und geben Sie das Ergebnis gemäß den Bedingungen aus". Es hat eine Eingabe- / Ausgabefunktion zum "Abrufen eines Bereichs numerischer Werte und Bedingungen und zum Ausgeben einer Zeichenfolge gemäß den Bedingungen".

Als nächstes kann in Bezug auf 2. ~ 4 gesagt werden, dass sie bis auf die spezifischen numerischen Werte und Zeichenfolgen dieselbe Funktion haben. Als Funktion scheint es, dass es in zwei Funktionen zerlegt werden kann: "Überprüfen Sie, ob es durch die angegebene Zahl teilbar ist (überprüfen Sie mit und ob es mehrere gibt)" und "Halten Sie die der Bedingung entsprechende Zeichenfolge".

Zusammenfassend wäre es schön, die folgenden drei Modelle zu haben.

3. Auswahl des Klassennamens

Nennen wir die drei oben genannten Modelle. Verwenden Sie den Namen so wie er ist als Klassennamen.

Name Funktion
Operator Rufen Sie eine Reihe von Zahlen und Bedingungen ab und geben Sie eine Zeichenfolge gemäß den Bedingungen aus
Specification Überprüfen Sie, ob es durch die angegebene Zahl teilbar ist
Operation Enthält die Zeichenfolge, die der Bedingung entspricht

Modelle wie Specification werden in Domain Driven Development (DDD) in einem Muster namens ** Specification Pattern ** eingeführt. Nachdem wir die erforderlichen Klassen haben, werden wir sie implementieren.

Implementierung

Basierend auf dem entworfenen Modell werden wir es in den Java-Code einfügen. (Da es von der zu verwendenden Seite platziert wird, unterscheidet es sich von der obigen Modellreihenfolge.)

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));
    }

}

Es gibt vier Hauptpunkte bei der Implementierung von "Specification.java":

--Implementiert als DDD-Spezifikationsmuster --Verwenden Sie das Prädikat von Java für den Teil, der die Bedingung ausdrückt

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);
        });
    }

}

Der Teil zur Überprüfung der Bedingung wird mit Stream in einen Liner geschrieben. Der Teil von .findFirst (). OrElse () muss ausgefüllt werden, um zu sehen, ob es einen besseren Weg gibt, ihn zu schreiben.

Ich werde auch den Code schreiben, um FizzBuzz mit der obigen Klasse auszuführen.

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;
    }

}

Wenn Sie sich FizzBuzz.java ansehen, können Sie sehen, dass die Rolle jeder Klasse klar ist und dass der Schreibstil mit der Problemstellung verknüpft ist. Selbst wenn es eine zusätzliche Spezifikation wie "Balken, wenn es ein Vielfaches von 7 ist" gibt, können Sie sich leicht vorstellen, wo Sie sie bearbeiten müssen. Dies ist der gute Punkt der objektorientierten Programmierung.

Zusammenfassung

Diesmal habe ich FizzBuzz objektorientiert geschrieben. Selbst bei einem so einfachen Problem war es sehr interessant, ernsthaft über die Objektorientierung nachzudenken. Nächstes Mal werde ich einen Test schreiben.

Der hier veröffentlichte Code ist auf Github zusammengefasst. Wenn Sie möchten, führen Sie ihn aus und versuchen Sie ihn erneut zu verbessern. (Und bitte Anfrage ziehen.) https://github.com/totto357/OOP-FizzBuzz

Der 12. Tag von morgen ist @ aimofs "FizzBuzz, das nur aus einzeiligen Funktionsdefinitionen besteht, ausgenommen Ausführungsanweisungen"!

Bonus

Es ist eine Implementierung im Builder-Muster der abgelehnten Operation-Klasse. Es schien gut zu sein, im Code ausdrücken zu können, dass "wenn ~~, wird es als xx angezeigt", aber ich lehnte es ab, weil es nicht wie "Java" aussah. Ich werde es jedoch verlassen, weil es eine große Sache ist.

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);
        }
    
    }

}

Beim Benutzen

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

Objektorientiertes FizzBuzz (Java)
[Java] Objektorientiert
[Java] Objektorientierte Zusammenfassung_Teil 1
[Java] Objektorientierte Syntax - Konstruktor
Objektorientierte (Java) Grundlagen
[Java] Objektorientierte Zusammenfassung_Teil 2
FizzBuzz in Java
[Java] Objektorientierte Syntax --Paket
Objektorientiert mit Strike Gundam (Java)
Objektorientierte Zusammenfassung von Anfängern (Java)
Java
Memorandum über Java 3-Hauptelemente (objektorientiert)
Java
[Java] Objektorientierte Syntaxklassenmethode / Argument
[Java] Objektorientierte Syntaxklasse / Feld / Methode / Bereich
Zusammenfassung der objektorientierten Programmierung mit Java
Ich habe Java und Rubys FizzBuzz verglichen.
Java lernen (0)
Java studieren ―― 3
[Java] -Array
Java geschützt
[Java] Anmerkung
[Java] Modul
Java studieren ―― 9
Java Scratch Scratch
Java-Tipps, Tipps
Java-Methoden
Java-Methode
Java (Konstruktor)
Java-Array
[Java] ArrayDeque
Java (überschreiben)
Java (Methode)
Objektorientierte Zusammenfassung
Java Day 2018
Java-Zeichenfolge
Java (Array)
Objekt orientierte Programmierung
Java statisch
Java-Serialisierung
Java Anfänger 4
JAVA hat bezahlt
Java studieren ―― 4
Java (gesetzt)
Java-Shell-Sortierung
[Java] compareTo
Java studieren -5
Java reflektierend 获 获 举
Java (Schnittstelle)
Java-Memorandum
Java-Array
Java studieren ―― 1
[Java] Array
[Java] Polymorphismus
Java # 0 studieren
Java-Überprüfung
Java-Framework
Java-Funktionen
[Java] Vererbung
FastScanner Java