Ich habe nicht viel angerührt, seit ich mit grundlegenden Informationen studiert habe, und zu diesem Zeitpunkt habe ich nicht versucht, Code zu schreiben, also habe ich beschlossen, wieder zu lernen.
Es zeigt, wie stark die Beziehung zwischen Modulen ist. Es wird gesagt, dass die Unabhängigkeit von Modulen erhöht werden kann, indem der Grad der Kopplung zwischen Modulen verringert wird. Eine erhöhte Modulunabhängigkeit hat folgende Vorteile:
Schauen Sie sich zum Beispiel den folgenden Code an. Diese Funktion bestimmt anhand des aktuellen westlichen Kalenders, ob es sich um ein feuchtes Jahr handelt.
from datetime import datetime
from calendar import isleap
#Eine Funktion, die bestimmt, ob dieses Jahr ein feuchtes Jahr ist und das Ergebnis ausgibt
def A():
this_year = datetime.now().year
if isleap(this_year):
print('Dieses Jahr ist ein feuchtes Jahr')
else:
print('Dieses Jahr ist kein feuchtes Jahr')
Angenommen, Sie möchten einen "Mechanismus zur Bestimmung, ob vor 10 Jahren ein feuchtes Jahr war" in dieses Modul integrieren.
from datetime import datetime
from calendar import isleap
#Eine Funktion, die bestimmt, ob dieses Jahr ein feuchtes Jahr ist und das Ergebnis ausgibt
def A():
this_year = datetime.now().year
if isleap(this_year):
print('Dieses Jahr ist ein feuchtes Jahr')
else:
print('Dieses Jahr ist kein feuchtes Jahr')
#Eine Funktion, die bestimmt, ob vor 10 Jahren ein feuchtes Jahr ist, und das Ergebnis ausgibt
def B():
this_year = datetime.now().year - 10
if isleap(this_year):
print('Vor 10 Jahren ist ein feuchtes Jahr')
else:
print('Vor 10 Jahren ist kein feuchtes Jahr')
Fast der gleiche Code ist geschrieben und fühlt sich intuitiv überhaupt nicht gut an. Außerdem treten beim Testen Probleme auf. Nehmen wir an, Sie möchten die folgenden Testdaten für Funktion A eingeben und testen, ob das Jahr der Schwellung richtig beurteilt wird.
Testdaten | Erwarteter Wert |
---|---|
2000 | Dieses Jahr ist ein feuchtes Jahr |
2020 | Dieses Jahr ist ein feuchtes Jahr |
2100 | Dieses Jahr ist kein feuchtes Jahr |
Wie testest du es?
Korrekt. Dies kann nicht getestet werden. Dies liegt daran, dass beide Funktionen A und B eine Mischung aus "Verarbeitung zum Finden des aktuellen Kalenders" und "Mechanismus zum Bestimmen des Jahres der Lauheit" aufweisen und ihre Funktionen nicht unabhängig sind.
Daher ist es besser, dies zu tun.
def A(year):
if isleap(year):
print('Dieses Jahr ist ein feuchtes Jahr')
else:
print('Dieses Jahr ist kein feuchtes Jahr')
Auf diese Weise sollten die Kalenderinformationen von außen eingegeben werden. Egal ob vor 10 Jahren, vor 100 Jahren oder vor 200 Jahren, Sie benötigen nur eine Funktion, unabhängig davon, ob Sie mehrere Testdaten haben.
Es gibt verschiedene Arten der Kopplung zwischen Modulen.
Evaluationskriterien | Kopplungsgrad zwischen Modulen | Modulunabhängigkeit |
---|---|---|
Innere Verbindung | hoch | Niedrig |
Gemeinsame Verbindung | ||
Äußere Verbindung | ||
Control Join | ||
Stempelkombination | ||
Datenverbindung | Niedrig | hoch |
Von hier aus werde ich es mit einem Code zusammenfassen. Dieses Mal werde ich es mit Python reproduzieren.
Dies ist heutzutage fast unmöglich und schwer zu reproduzieren ... Ist es so, wenn du es erzwingst?
Es gibt ein solches Modul. Benutzername, Level, Angriff, Verteidigung usw. werden als globale Variablen definiert.
moduleA.py
username = 'hogehogekun'
level = 25
attack = 20
defence = 5
def show_user_status():
print('Nutzername:' + username)
print('Niveau:' + str(level))
print('Offensivkraft:' + str(attack))
print('Verteidigungskraft:' + str(defence))
Angenommen, Sie haben Code, der dies ausnutzt.
main.py
import moduleA
#Erhöhen Sie das Level um 1
moduleA.level += 1
#Status mit der Funktion moduleA anzeigen
moduleA.show_user_status()
Ergebnis
Benutzername: hogehogekun
Stufe: 26
Angriffskraft: 20
Verteidigung: 5
Der Anfangswert des Levels war 25, aber er hat sich um 1 erhöht. Es gibt kein Problem mit dem Verhalten, aber das Verhalten von Modul A hängt stark vom Verhalten des Hauptmoduls ab.
Angenommen, Sie haben Benutzerinformationen in einer Klasse zusammengefasst und in einer Liste verwaltet.
moduleA.py
class User:
def __init__(self, username, level, attack, defence):
self.username = username
self.level = level
self.attack = attack
self.defence = defence
def show_user_status(self):
print('Nutzername:' + self.username)
print('Niveau:' + str(self.level))
print('Offensivkraft:' + str(self.attack))
print('Verteidigungskraft:' + str(self.defence))
#Verwalten Sie die Liste der Benutzer in einer Liste
user_list = [User('hogehogekun', 75, 90, 80), User('fugafugakun', 10, 5, 7)]
Angenommen, in mainA gibt es zwei Funktionen, die dieses Modul verwenden.
mainA.py
import moduleA
def funcA():
del(moduleA.user_list[0])
def funcB():
print(moduleA.user_list[0].username)
#In der Reihenfolge funcA, funcB ausführen
funcA()
funcB()
Ergebnis
fugafugakun
Vielleicht hat funcA diesmal das erste Element der globalen Liste gelöscht. Als funcB einen Blick darauf warf, war Hogehoge bereits verschwunden und hinterließ nur noch Fugafuga. Wenn funcB auf moduleA.user_list [1] verweist, tritt übrigens IndexError auf. Auf diese Weise müssen Sie beim gemeinsamen Join, wenn Sie einen Teil der gemeinsamen Datenstruktur ändern oder löschen, alle Module überprüfen, die auf den gemeinsamen Teil verweisen.
Sehr ähnlich einem allgemeinen Join, aber die Wahrnehmung, dass die gemeinsam genutzten Informationen eher eine Sammlung einzelner Daten als eine Datenstruktur wie eine Liste oder ein Objekt sind.
Nehmen wir diesmal an, dass Informationen zur kumulierten Benutzeranzahl und zum Dienststatus vorliegen.
moduleA.py
class User:
def __init__(self, username, level, attack, defence):
self.username = username
self.level = level
self.attack = attack
self.defence = defence
def show_user_status(self):
print('Nutzername:' + self.username)
print('Niveau:' + str(self.level))
print('Offensivkraft:' + str(self.attack))
print('Verteidigungskraft:' + str(self.defence))
user_count = 123091 #Kumulierte Anzahl von Benutzern
service_status = 200 #Service Status
main.py
import moduleA
def funcA():
print(moduleA.user_count)
def funcB():
print(moduleA.service_status)
funcA()
funcB()
Ergebnis
123091
200
Dieser Code hat keine Verhaltensprobleme. Sowohl die Anzahl der Benutzer als auch der Servicestatus wurden in funcA und funcB korrekt erfasst. Wenn jedoch eine Spezifikationsänderung wie der service_status von moduleA.py zu einem Zeichentyp anstelle eines numerischen Typs wird, muss funcB geändert werden, das auf die entsprechenden Informationen verweist.
Control Join verwendet Argumente, um die Verarbeitung der aufgerufenen Funktion zu steuern. In diesem Code wird eine unterschiedliche Verarbeitung durchgeführt, je nachdem, ob 1 oder 2 an some_command übergeben wird.
moduleA.py
class User:
def __init__(self, username, level, attack, defence):
self.username = username
self.level = level
self.attack = attack
self.defence = defence
def some_command(self, command_id):
if command_id == 1: #Befehl zur Statusanzeige
print('Nutzername:' + self.username)
print('Niveau:' + str(self.level))
print('Offensivkraft:' + str(self.attack))
print('Verteidigungskraft:' + str(self.defence))
elif command_id == 2: #Level-up-Befehl
print(self.username + 'Level wurde um 1 erhöht!')
self.level += 1
main.py
from moduleA import User
user1 = User('hogehogekun', 40, 20, 20)
user1.some_command(1)
user1.some_command(2)
Ergebnis
Benutzername: hogehogekun
Stufe: 40
Angriffskraft: 20
Verteidigung: 20
Das Level von Hogehogekun wurde um 1 erhöht!
Auf den ersten Blick sieht es gut aus, weil die als Befehl bezeichneten Informationen von außen weitergegeben werden. Ein anderes Modul, das some_command aufruft, muss die interne Struktur von some_command kennen. Daher ist der Kopplungsgrad relativ hoch.
Benutzerklasse wie gewohnt. Dieses Mal konzentrieren wir uns auf den Austausch zwischen funcA und funcB in main.py. Das Aufrufen von funcB in funcA und das Übergeben einer Liste als Argument sieht aus wie eine Art Code.
moduleA.py
class User:
def __init__(self, username, level, attack, defence):
self.username = username
self.level = level
self.attack = attack
self.defence = defence
def show_user_status(self):
print('Nutzername:' + self.username)
print('Niveau:' + str(self.level))
print('Offensivkraft:' + str(self.attack))
print('Verteidigungskraft:' + str(self.defence))
Angenommen, ein anderes Modul verhält sich so.
main.py
from moduleA import User
def funcA():
user_list = [User('hogehogekun', 20, 10, 10), User('fugafugakun', 99, 99, 99), User('piyopiyokun', 99, 99, 99)]
funcB(user_list)
def funcB(user_list):
print(user_list[2].username)
funcA()
Ergebnis
piyopiyokun
An dieser Stelle ist daran nichts auszusetzen, aber wenn sich beispielsweise die Anzahl der Elemente in funcA ändert, ist funcB betroffen.
main.py
def funcA():
user_list = [User('hogehogekun', 20, 10, 10), User('fugafugakun', 99, 99, 99)]
funcB(user_list)
def funcB(user_list):
print(user_list[2].username)
funcA()
Ergebnis
IndexError: list index out of range
In der Stempelkombination wird die gesamte Liste übergeben, das aufrufende Modul verwendet jedoch nur einige Informationen. Dieses Mal verwendet funcB nur das dritte Element, obwohl ihm eine Liste mit drei Elementen übergeben wird. Zu diesem Zeitpunkt kann funcB betroffen sein, selbst wenn sich die Elemente ändern, die nicht auf der funcB-Seite (in diesem Fall die Nummer) in der Stempelkombination verwendet werden.
Minimiert die zwischen mehreren Modulen übertragenen Informationen. Nach dem Beispiel einer Stempelkombination sieht es so aus.
moduleA.py
class User:
def __init__(self, username, level, attack, defence):
self.username = username
self.level = level
self.attack = attack
self.defence = defence
def show_user_status(self):
print('Nutzername:' + self.username)
print('Niveau:' + str(self.level))
print('Offensivkraft:' + str(self.attack))
print('Verteidigungskraft:' + str(self.defence))
main.py
def funcA():
user_list = [User('hogehogekun', 20, 10, 10), User('fugafugakun', 99, 99, 99), User('piyopiyokun', 99, 99, 99)]
funcB(user_list[2])
def funcB(target_user):
print(target_user.username)
funcA()
Ergebnis
piyopiyokun
Da funcB nur piyopiyokun verarbeitet, sind die zu übergebenden Daten in erster Linie nur user_list [2]. Wenn dies die Anzahl der Benutzerlisten verringert, sollte dies funcA, nicht jedoch funcB betreffen. Erstens bedeutet die Verringerung der Anzahl der Benutzerlisten, dass funcA geändert wird, sodass der Einflussbereich erheblich kleiner sein kann.
Auf diese Weise kann der Kopplungsgrad von Modulen geschwächt werden, indem nur die erforderlichen Informationen ausgetauscht werden.
Nachtrag: Als ich das Buch las, das ich hatte, hieß es: "Das aufrufende Modul kann die aufrufenden Daten mit den empfangenen Argumenten direkt bearbeiten." Mit anderen Worten, es scheint, dass Sie als Referenz übergeben sollten. Je nach Entwickler und Entwicklungsmethode schien es hier unterschiedliche Denkweisen zu geben.
Es gibt verschiedene Vorteile, wenn die Stärke der Module hoch und der Grad der Kopplung zwischen den Modulen niedrig eingestellt wird.
Und so weiter!
Recommended Posts