Hier sind einige Tipps zum Schreiben von Code, der einfach zu warten / zu testen ist.
Die Sprache ist übrigens in Java geschrieben (bitte lesen Sie andere Sprachen)
Möglicherweise verstehen Sie auch, dass der Verbindungsgrad falsch ist. In diesem Fall weisen Sie bitte darauf hin. (Weil es sich von anderen Dingen unterscheidet, die von Büchern und Websites geschrieben wurden ... (´ ・ ω ・ `))
Wird auch als Modulstärke bezeichnet. Ein Maß dafür, wie sehr sich ein Code auf die Aufteilung der Verantwortlichkeiten für diese Klasse konzentriert. ** Klassen, die nur für eine Rolle existieren (alle Methoden existieren nur für diese Rolle), sind sehr kohärent. ** ** ** Im Gegenteil, die Klassen, die in jeder Methode keine Gemeinsamkeiten haben und verschiedene Rollen spielen, weisen einen geringen Aggregationsgrad auf.
Wenn der Aggregationsgrad niedrig ist, ist die Anzahl der Mitgliedsvariablen tendenziell groß. Da die Mitgliedsvariable der Zustand der Klasse selbst ist, nimmt bei vielen Mitgliedsvariablen das Muster des Zustands, den die Instanz annehmen kann, zu, die Komplexität nimmt zu und die Wartbarkeit wird erheblich verringert. Es macht auch das Testen schwieriger und mehr Muster.
Diese Klasse existiert nur zum "Behandeln von Zeichenfolgen" und hat keine andere Rolle. String-Klasse
Betrachten Sie eine Klasse namens Price. Die Klasse verfügt nur über Methoden, die Preisdaten verarbeiten.
public class Price {
private final int value;
public Price(int value) {
this.value = value;
}
public Price() {
this(0);
}
/**Preis hinzufügen*/
public Price add(Price other) {
return new Price(this.value + other.value);
}
/**Den Preis ausgeben*/
public Price multiply(int amount) {
return new Price(this.value * amount);
}
/**Rabatt*/
public Price discount(double percentage) {
return new Price(this.value * percentage);
}
/**Formatieren Sie den Preis und geben Sie ihn zurück*/
public String format() {
return NumberFormat.getCurrencyInstance().format(this.value);
}
public void print() {
System.out.println(this.format());
}
}
//Benutzerseite
Price price = new Price(1000);
price.print(); // ¥1,000
System.out.println(price.format()); // ¥1,000
System.out.println(price.add(new Price(500)).format()); // ¥1,500
System.out.println(price.discount(0.9).format()); // ¥900
//Ergänzung:Der Preis ist unveränderlich und der anfänglich eingestellte Wert ändert sich nicht
//Wert beim Aufrufen des letzten Rabattes=Die Berechnung erfolgt bei 1000
Einfach ausgedrückt: "** Wie viel der Benutzer und die Benutzerklassen und -methoden wissen (von wie viel sie abhängen) **".
Je höher der Kopplungsgrad ist, desto weniger wartbar ist er und desto schwieriger ist es zu testen.
Der Kopplungsgrad steigt in der folgenden Reihenfolge an.
Es ruft nur Methoden ohne Argumente auf und hat keinen Rückgabewert. Die ideale Form.
public class Main {
private final Price price;
public Main(Price price) {
this.price = price;
}
public void output() {
this.price.print();
}
}
Price price = new Price(1000);
Main main = new Main(price);
main.output(); // ¥1,Wird als 000 angezeigt
Oben teilen sich die Klasse "Main" und die Klasse "Price" keine Daten, und "Main # output ()" hängt nicht von der Implementierung von "print ()" ab.
Die "Price" -Klasse weiß nichts über die "Main" -Klasse, und die "Main" -Klasse kümmert sich auch nicht darum, was "Price # print ()" im Inneren tut. ** Selbst wenn Sie beispielsweise die Implementierung der Methode "print ()" ändern, um eine Zeichenfolge in eine Datei zu drucken, ist es "Main # output" egal, selbst wenn Sie nichts tun. ** ** **
Solche Verknüpfungen werden auch als "Message Passing" bezeichnet, und Interaktionen zwischen solchen Objekten werden als "Messaging" bezeichnet. Es wurde "Messaging" genannt, weil es die Arbeit vollständig an das andere Objekt delegiert und es ist, als würde man jemandem sagen, "das ist endlich erledigt".
Übergeben Sie nur einfache Daten.
//Beispiel für Datenverknüpfung
public class NameFormatter {
public String format(String firstName , String familyName) {
return new StringBuilder().add(familyName).add(" ").add(firstName).toString();
}
}
public class Main {
private final String firstName;
private final String familyName;
public Main(String firstName, String familyName) {
this.firstName = firstName;
this.familyName = familyName;
}
public void printName() {
NameFormatter formatter = new NameFormatter();
System.out.println(formatter.format(this.firstName, this.familyName));
}
}
Main main = new Main("Kazuki", "Oda");
main.printName(); //Kazuki Oda
Die Kombination mit NameFormatter
in Main # printName ()
oben ist eine Datenkombination.
Teilen Sie bei der Datenbindung ** nur "notwendige Informationen" ** mit. Die hier genannten "Informationen" entsprechen den folgenden.
Die Datenbindung führt immer zu derselben Ausgabe für dieselbe Eingabe. Da nur die erforderlichen Informationen an "NameFormatter" übergeben werden, verwendet "printName ()" nur den Wert, der schließlich vom "NameFormatter # -Format" zurückgegeben wird, und welche Art der Implementierung intern erfolgt. Sie müssen nicht wissen, ob Sie dort sind.
Im Allgemeinen werden Daten zusammengefügt, um Daten als Argument [unveränderlich] zu übergeben (https://ja.wikipedia.org/wiki/%E3%82%A4%E3%83%9F%E3%83%A5%E3%83] % BC% E3% 82% BF% E3% 83% 96% E3% 83% AB) oder [Primitiver Typ](https://ja.wikipedia.org/wiki/%E3%83%97%E3%83% AA% E3% 83% 9F% E3% 83% 86% E3% 82% A3% E3% 83% 96% E5% 9E% 8B) Oder bezieht sich auf einen Join beim Übergeben einer Schnittstelle (glaube ich). Selbst im Fall der Übergabe eines Objekts vom Referenztyp kann es jedoch einer Datenbindung entsprechen (zum Beispiel werden nur die erforderlichen Informationen durch das aufgerufene Verfahren offenbart).
Übergeben Sie eine Datenstruktur (dh eine Instanz mit mehreren Mitgliedsvariablen) als Argument.
public class Item {
//In dem Körper gibt es einen Konstruktor, Getter und Setter
private String name;
private String group;
}
public class CashRegister {
public String format(Item item, Price price) {
return item.getName() + ":" + price.format();
}
}
CashRegister regi = new CashRegister();
System.out.println(regi.format(new Item("Smash Bra", "Spiel"), new Price(6800))); //Smash Bra:¥6,800
Bei einer Stempelkombination können Daten, die nicht vom Angerufenen verwendet werden, in der Struktur referenziert werden (dh der Angerufene kennt auch unnötige Informationen). Im obigen Fall wird "Gruppe" nicht verwendet, aber wenn Sie dies möchten, können Sie im "CashRegister # -Format" auf eine von ihnen verweisen.
Es spielt keine Rolle, ob es sich nur um eine Referenz handelt, aber in einigen Fällen ist es möglich, den Wert der Daten in der aufgerufenen Methode neu zu schreiben. Also ** Bei einer Stempelkombination, wenn der Anrufer sie korrekt verwenden möchte, gibt es Fälle, in denen es erforderlich ist, bis zu einem gewissen Grad zu wissen, welche Daten in der aufgerufenen Methode verarbeitet werden. ** ** **
Das Obige ist eine Datenkombination mit dem Anrufer, wenn CashRegister wie folgt eingestellt ist. Anrufer und Artikel sowie Anrufer und Preis werden jedoch zusammen gestempelt </ font>
public class CashRegister {
public String format(String item, int price) {
return item + ":" + price;
}
}
CashRegister regi = new CashRegister();
Item item = new Item("Smash Bra", "Spiel");
Price price = new Price(6800);
System.out.println(regi.format(item.getName(), price.format())); //Smash Bra:¥6,800
Daher kann die Stempelbindung nicht einfach beseitigt werden, solange die Klasse verwendet wird. Durch die Verwendung der Schnittstelle ist es möglich, den Grad der Bindung an Datenbindung oder Nachrichtenbindung zu verringern, dieser wird jedoch länger sein, sodass ich ihn weglassen werde.
Ein Fall, in dem sich der Rückgabewert abhängig vom Inhalt des angegebenen Arguments ändert.
public class Item {
//In dem Körper gibt es einen Konstruktor, Getter und Setter
private String name;
private Price unitPrice;
}
public class SaleService {
public Price fixPrice(Item item, int amount, boolean discount) {
Price newPrice = item.getUnitPrice().multiply(amount);
if (discount == false) {
return newPrice;
}
return newPrice.discount(0.90);
}
}
Item item = new Item("Smash Bra", new Price(6800));
SaleService service = new SaleService();
System.out.prinln(service.fixPrice(item, 2, false)); // ¥13,600
System.out.prinln(service.fixPrice(item, 2, true)); // ¥12,240
In dieser Steuerkombination unterscheidet sich der Rückgabewert durch die Anzahl der Muster, selbst wenn ein ähnlicher Wert als Argument eingegeben wird, abhängig von den Mustern, die verwendet werden können. Mit anderen Worten, ** die Muster, die genommen werden können, hängen von den Argumenten ab. ** ** **
Diese Kontrollbindung kann durch Verwendung von Polymorphismus auf weniger als die Stempelbindung reduziert werden. (Ich persönlich denke jedoch, dass eine Steuerkopplung toleriert werden kann, wenn es sich um 3 bis 4 Muster handelt.)
Der äußere Join bezieht sich auf den Status, in dem sich mehrere Module auf eine globale Ressource beziehen. Wenn Sie diesen Beitritt von nun an zulassen, ist es sehr schwierig, ihn zu testen.
Die globalen Ressourcen beziehen sich beispielsweise auf Folgendes.
Für diese wirkt sich der in anderen Instanzen usw. geänderte Wert auf die gesamte Klasse aus, auf die von anderen verwiesen wird. Wenn sich die Struktur dieser Ressourcen ändert, müssen alle aufrufenden Klassen geändert werden.
** Um testbaren Code zu schreiben, ist es wichtig (glaube ich), wie die Anzahl der Bindungen nach dieser äußeren Verknüpfung verringert werden kann. ** ** **
Ein Zustand, in dem verschiedene Klassen auf mehrere Daten globaler Ressourcen verweisen. Es wird chaotischer sein als die äußere Verbindung.
Ein Join, der sogar die privaten Methoden und Variablennamen anderer Klassen kennt und diese direkt referenziert / aufruft. Wenn sich in der Inhaltskombination die interne Implementierung (unveröffentlichte Implementierung) der abhängigen Klasse ändert, ist dies direkt betroffen. Selbst wenn der Variablenname der Abhängigkeit geändert wird, ist dies betroffen.
Unter Berücksichtigung der folgenden Punkte kann der Kopplungsgrad niedrig gehalten werden.
Einfach ausgedrückt, die Nummer von "if-Anweisung / for-Anweisung / while-Anweisung / switch-Anweisung / try-Anweisung / catch-Anweisung" und so weiter. Wenn es keine von ihnen gibt, ist es 1, und wenn die Anzahl der Zweige zunimmt, nimmt sie um 1 zu. Beispielsweise beträgt die zyklische Komplexität des folgenden Verfahrens 4.
public void hogehoge(int test) {
if (test > 5 ) {
// doSomething1
} else if (test < 1) {
// doSomething2
}
for (int i = 0; i < 5; i++) {
// doSomething3
}
}
Natürlich gibt es mehr Testmuster. Darüber hinaus wird die Lesbarkeit verringert und die Wartung wird schwierig.