Um meine TDD-Kenntnisse zu verbessern, habe ich einige der in diesem Blog zusammengefassten Themen und Routensuche Ich habe persönlich ein erfrischendes Refactoring durchgeführt, daher werde ich es für Ihre Unterlagen zusammenfassen.
Außerdem besteht die Aufgabe darin, bis zu 4 zu implementieren, und hier beschreiben wir das Refactoring in 3 bis 4.
Java Verwenden Sie OpenJDK 11. Da es sich um einen Mac handelt, wurde er mit "Home Brew Cask Java" installiert
Maven Verwenden Sie 3.6.0. Dies wurde auch mit Homebrew installiert
IDE Verwenden Sie IntelliJ IDEA 2018.3.
Stellen Sie in den Projekteinstellungen ein, dass es mit dem oben genannten OpenJDK oder Maven ausgeführt wird
Testen Sie Set JUnit5, Pom, um AsserJ für die Assertion zu verwenden
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>myTest</groupId>
<artifactId>myTest</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>11</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.3.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.3.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.11.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Testcode bis Übung 4
TrainPathTest.java
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
class TrainPathTest {
private TrainPath trainPath;
@BeforeEach
void createTrainPath() {
trainPath = new TrainPath();
}
@Test
@DisplayName("Oshima kann nicht mit dem Zug von Yokohama aus erreicht werden")
void cannotFromYokohamaToOshima() {
assertThat(trainPath.exist("Yokohama", "Oshima")).as("YokohamaからOshimaへは行けない").isFalse();
}
@Test
@DisplayName("Sie können nicht mit dem Zug von Oshima nach Yokohama fahren")
void cannotFromOshimaToYokohama() {
assertThat(trainPath.exist("Oshima", "Yokohama")).as("OshimaからYokohamaへは行けない").isFalse();
}
@Test
@DisplayName("Sie können mit dem Zug von Yokohama nach Tokio fahren")
void canGoFromYokohamaToTokyo() {
assertThat(trainPath.exist("Yokohama", "Tokio")).as("YokohamaからTokioへ行ける").isTrue();
}
@Test
@DisplayName("Sie können mit dem Zug von Tokio nach Yokohama fahren")
void canGoFromTokyoToYokohama() {
assertThat(trainPath.exist("Tokio", "Yokohama")).as("TokioからYokohamaへ行ける").isTrue();
}
@Test
@DisplayName("Omiya kann mit dem Zug von Tokio aus erreicht werden")
void canGoFromTokyoToOmiya() {
assertThat(trainPath.exist("Tokio", "Omiya")).as("TokioからOmiyaへ行ける").isTrue();
}
@Test
@DisplayName("Sie können mit dem Zug von Omiya nach Tokio fahren")
void canGoFromOmiyaToTokyo() {
assertThat(trainPath.exist("Omiya", "Tokio")).as("OmiyaからTokioへ行ける").isTrue();
}
@Test
@DisplayName("Yokohama kann mit dem Zug von Omiya aus erreicht werden")
void canGoFromOmiyaToYokohama() {
assertThat(trainPath.exist("Omiya", "Yokohama")).as("OmiyaからYokohamaは行ける").isTrue();
}
@Test
@DisplayName("Omiya kann mit dem Zug von Yokohama aus erreicht werden")
void canGoFromYokohamaToOmiya() {
assertThat(trainPath.exist("Yokohama", "Omiya")).as("YokohamaからOmiyaは行ける").isTrue();
}
@Test
@DisplayName("Akabane kann mit dem Zug von Kawasaki aus erreicht werden")
void canGoFromKawasakiToAkabane() {
assertThat(trainPath.exist("Kawasaki", "Akabane")).as("KawasakiからAkabaneは行ける").isTrue();
}
}
Zwei Klassen
Punkte, über die man sich Sorgen machen muss
――Da Sie es nicht auf einer Route erreichen können, habe ich wiederholt gesucht, während ich einen Wegpunkt genommen habe.
TrainPath.java
import java.util.ArrayList;
import java.util.List;
class TrainPath {
private final List<Section> sectionList;
TrainPath() {
sectionList = new ArrayList<>();
sectionList.add(new Section("Yokohama", "Tokio"));
sectionList.add(new Section("Tokio", "Omiya"));
}
boolean exist(String departure, String destination) {
List<String> stations = new ArrayList<>();
stations.add(departure);
while (true) {
List<String> transitList = new ArrayList<>();
for (String startStation : stations) {
for (Section section : sectionList) {
if (section.isSearched()) {
continue;
}
if (section.exist(startStation, destination)) {
return true;
}
String transit = section.getTargetStation(startStation);
if (transit == null) {
continue;
}
if (transitList.contains(transit)) {
continue;
}
transitList.add(transit);
section.setSearched();
}
}
if (transitList.isEmpty()) {
return false;
}
stations.clear();
stations = new ArrayList<>(transitList);
}
}
}
Section.java
class Section {
private String station1;
private String station2;
private boolean searched;
Section(String station1, String station2) {
this.station1 = station1;
this.station2 = station2;
this.searched = false;
}
boolean exist(String departure, String destination) {
if (station1.equals(departure) && station2.equals(destination)) {
return true;
}
return station2.equals(departure) && station1.equals(destination);
}
String getTargetStation(String station) {
if (station.equals(this.station1)) {
return this.station2;
} else if (station.equals(this.station2)) {
return this.station1;
}
return null;
}
boolean isSearched() {
return searched;
}
void setSearched() {
this.searched = true;
}
}
Methodenteilung von TrainPath Während der Anweisungsverarbeitung
Ich denke, es wurde einfacher zu verstehen, indem man die Methode aufteilte.
TrainPath.java
import java.util.ArrayList;
import java.util.List;
class TrainPath {
private final List<Section> sectionList;
private List<String> transitList;
TrainPath() {
sectionList = new ArrayList<>();
initializeSection();
}
boolean exist(String departure, String destination) {
List<String> stations = new ArrayList<>();
stations.add(departure);
while (true) {
transitList = new ArrayList<>();
for (String station : stations) {
if (existSection(station, destination)) return true;
}
if (transitList.isEmpty()) return false;
stations = new ArrayList<>(transitList);
}
}
//Suchen Sie nach einer direkten Route von Ihrem Ursprung zu Ihrem Ziel
//Wenn es keine direkte Route gibt, suchen Sie nach einem Wegpunkt
private boolean existSection(String departure, String destination) {
for (Section section : sectionList) {
if (section.isSearched()) continue;
if (section.exist(departure, destination)) return true;
existTransit(departure, section);
}
return false;
}
//Suchen Sie nach Wegpunkten auf der Route
private void existTransit(String departure, Section section) {
String transit = section.getTargetStation(departure);
if (transit == null) return;
if (transitList.contains(transit)) return;
transitList.add(transit);
section.setSearched();
}
private void initializeSection() {
sectionList.add(new Section("Yokohama", "Tokio"));
sectionList.add(new Section("Tokio", "Omiya"));
}
}
Zum Zeitpunkt von Übung 3 wurde dies realisiert, sodass ich den Test durch Hinzufügen der Routenliste bestehen konnte.
TrainPath.java
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
class TrainPath {
private final List<Section> sectionList = new ArrayList<>();
private List<String> transitList;
TrainPath() {
initializeSection();
}
boolean exist(String departure, String destination) {
List<String> stations = Collections.singletonList(departure);
while (true) {
transitList = new ArrayList<>();
for (String station : stations) {
if (existSection(station, destination)) return true;
}
if (transitList.isEmpty()) return false;
stations = new ArrayList<>(transitList);
}
}
//Suchen Sie nach einer direkten Route von Ihrem Ursprung zu Ihrem Ziel
//Wenn es keine direkte Route gibt, suchen Sie nach einem Wegpunkt
private boolean existSection(String departure, String destination) {
for (Section section : sectionList) {
if (section.isSearched()) continue;
if (section.exist(departure, destination)) return true;
existTransit(departure, section);
}
return false;
}
//Suchen Sie nach Wegpunkten auf der Route
private void existTransit(String departure, Section section) {
String transit = section.getTargetStation(departure);
if (transit == null) return;
if (transitList.contains(transit)) return;
transitList.add(transit);
section.setSearched();
}
private void initializeSection() {
sectionList.add(new Section("Yokohama", "Musashi Kosugi"));
sectionList.add(new Section("Yokohama", "Kawasaki"));
sectionList.add(new Section("Musashi Kosugi", "Nishikokubunji"));
sectionList.add(new Section("Musashi Kosugi", "Shibuya"));
sectionList.add(new Section("Musashi Kosugi", "Kawasaki"));
sectionList.add(new Section("Kawasaki", "Tokio"));
sectionList.add(new Section("Nishikokubunji", "Minamiurawa"));
sectionList.add(new Section("Nishikokubunji", "Shinjuku"));
sectionList.add(new Section("Shibuya", "Shinjuku"));
sectionList.add(new Section("Shibuya", "Tokio"));
sectionList.add(new Section("Tokio", "Ochanomizu"));
sectionList.add(new Section("Tokio", "Akihabara"));
sectionList.add(new Section("Shinjuku", "Ikebukuro"));
sectionList.add(new Section("Shinjuku", "Ochanomizu"));
sectionList.add(new Section("Ochanomizu", "Akihabara"));
sectionList.add(new Section("Akihabara", "Tabata"));
sectionList.add(new Section("", ""));
sectionList.add(new Section("", ""));
sectionList.add(new Section("", ""));
sectionList.add(new Section("Akabane Ikebukuro Tabata Tabata Akabane Akabane", "Minamiurawa"));
sectionList.add(new Section("Minamiurawa", "Omiya"));
}
}
Obwohl ich die Methode geteilt habe, konnte ich das Gefühl, aggressiv zu sein, nicht leugnen, und ich hatte das Gefühl, dass die Verantwortung für die Methode nicht klar war.
Während meiner Recherche habe ich etwas über rekursive Aufrufe des Codes gelernt. Wenn ich dies verwenden würde, würde ich dann keine Liste mit Via-Werten benötigen? Ich dachte und versuchte umzugestalten.
Punkt
Ich konnte sehr klar schreiben. Durch das Ausschließen von Routen, die nicht im Voraus mithilfe der Stream-API durchsucht werden müssen, kann die Logik in der for-Anweisung des Suchprozesses nur auf den Beurteilungsprozess reduziert werden.
Für StreamAPI habe ich auch in Betracht gezogen, removeIf für Collection zu verwenden, aber ich habe dieses Formular ausgewählt, da es die erforderliche Route löscht, wenn sich der Wegpunkt ändert.
TrainPath.java
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
class TrainPath {
private final List<Section> sectionList = new ArrayList<>();
TrainPath() {
initializeSection();
}
boolean exist(String departure, String destination) {
//Schließen Sie nicht durchsuchte Routen aus
List<Section> filteredSectionList = sectionList.stream()
.filter(section -> section.isNeedSearch(departure))
.collect(Collectors.toList());
for (Section section : filteredSectionList) {
if (section.exist(departure, destination)) return true;
sectionList.remove(section);
//Suchen Sie erneut auf der Route, die durch das Ziel der Route führt
String transit = section.getDestination(departure);
if (exist(transit, destination)) return true;
}
return false;
}
private void initializeSection() {
//Kürzung
}
}
In Section.java wurde die Beurteilungslogik der Filterverarbeitung der Stream-API von TrainPath hinzugefügt.
Section.java
class Section {
private String station1;
private String station2;
Section(String station1, String station2) {
this.station1 = station1;
this.station2 = station2;
}
boolean exist(String departure, String destination) {
if (station1.equals(departure) && station2.equals(destination)) {
return true;
}
return station2.equals(departure) && station1.equals(destination);
}
String getDestination(String departure) {
if (departure.equals(this.station1)) {
return this.station2;
} else if (departure.equals(this.station2)) {
return this.station1;
}
return null;
}
boolean isNeedSearch(String departure) {
return departure.equals(this.station1) || departure.equals(this.station2);
}
}
Wenn Sie einen Testcode schreiben, können Sie sicher umgestalten. Dieses Mal habe ich die Logik in umgekehrter Reihenfolge mit der Methode geschrieben, die einen Booleschen Wert zurückgibt, aber ich konnte den Fehler leicht finden, da der Test fehlgeschlagen ist. Bis jetzt dauerte die Inspektion lange, indem sie tatsächlich verschoben oder im Debug-Modus überprüft wurde, und der Test enthielt viele Auslassungen. Außerdem war das Ausführen und Überprüfen des Testcodes im Debug-Modus einfacher zu beheben, da die Punkte für die Überprüfung auf Probleme im Vergleich zur Überprüfung im herkömmlichen Debug-Modus eingegrenzt wurden.
Bei der Verarbeitung mit derselben Methode beim Ändern verwandter Parameter wie Eltern und Kind vereinfacht die Verwendung des rekursiven Aufrufs der Methode den Code und erleichtert das Anzeigen. Wenn Sie dagegen nicht daran gewöhnt sind, werden Sie verwirrt darüber sein, wie der Rückgabewert an den Anrufer zurückgegeben wird.
Durch die Verarbeitung der Vorverarbeitung, die in der for-Anweisung im Voraus unter Verwendung der Stream-API durchgeführt wurde, kann die Vorverarbeitung verzweigt werden, und die Vorverarbeitung, die in der for-Anweisung durchgeführt wird, wird einfach und leicht verständlich. Eigentlich wäre es schön, wenn die gesamte Verarbeitung der for-Anweisung mit der Stream-API durchgeführt werden könnte, aber ich war der Meinung, dass es sehr effektiv wäre, nur das, was ich tun könnte, aufzuteilen, ohne es in die Stream-API zu übertreiben.
Dieses Mal habe ich versucht, durch verschiedene Versuche und Irrtümer umzugestalten, aber ich denke, es gibt einen besseren Weg, es zu schreiben. Ich glaube jedoch, dass ich noch nicht ausgereift bin, um es zu bemerken, und ich hatte das Gefühl, dass ich immer mehr Code schreiben und viel wissen musste.
Recommended Posts