2010-03-11 13 views
5

Nach ein paar Wochen in diesem Forum zu lesen, dachte ich, es war Zeit für mich, meinen ersten Beitrag zu machen.Code Complete 2ed, Zusammensetzung und Delegation

Ich lese gerade Code Complete. Ich denke es sind 15 Jahre seit dem letzten Mal, und ich finde, dass ich immer noch keinen Code schreiben kann ;-)

Wie auch immer auf Seite 138 in Code Complete findest du dieses Coding Horror Beispiel. (Ich habe einen Teil des Codes entfernt)

class Emplyee { 
public: 
FullName GetName() const; 
Address GetAddress() const; 
PhoneNumber GetWorkPhone() const; 
... 

bool IsZipCodeValid(Address address); 
... 

private: 
    ... 
} 

Was Steve denkt schlecht ist, dass die Funktionen lose verwandt sind. Oder hat er geschrieben: "Es gibt keine logische Verbindung zwischen Mitarbeitern und Routinen, die Postleitzahlen, Telefonnummern oder Berufsklassifikationen überprüfen"

Ok, ich stimme ihm vollkommen zu. Vielleicht ist etwas wie das folgende Beispiel besser.

class ZipCode 
{ 
public: 
bool IsValid() const; 
    ... 
} 

class Address { 
public: 
    ZipCode GetZipCode() const; 
    ... 
} 

class Employee { 
public: 
Address GetAddress() const; 
    ... 
} 

Wenn Sie überprüfen, ob die Zip-Datei gültig ist, müssten Sie so etwas tun.

employee.GetAddress().GetZipCode().IsValid(); 

Und das ist nicht gut in Bezug auf die Law of Demeter.

Wenn Sie also zwei der drei Punkte entfernen möchten, müssen Sie Delegation und ein paar Wrapper-Funktionen wie folgt verwenden.

Aber dann wieder haben Sie Routinen, die keine logische Verbindung hat.

Ich persönlich denke, dass alle drei Beispiele in diesem Beitrag schlecht sind. Ist es eine andere Art, über die ich nicht nachgedacht habe?

+0

Ich kenne viele Programmierer lieben Code abgeschlossen, aber ehrlich gesagt habe ich nie getan. Es war eine sehr langweilige Lektüre. – JonH

+0

Das hängt davon ab, wann Sie es lesen. Wenn Sie ein Junior-Entwickler sind, ist es eine gute Lektüre.Wenn Sie ein erfahrener Entwickler sind, denke ich, dass die Dinge, die im Buch geschrieben sind, nur Sinn ergeben, ohne etwas Außergewöhnliches zu sein. –

+1

@JonH Ich stimme zu - sein bestes Buch ist eigentlich "Rapid Development", was nur wenige Leute gelesen zu haben scheinen - es ist großartig. –

Antwort

1

Es ist jetzt später gegen Bezahlung zahlen.

Sie können die Delegation und die Wrapper-Funktionen im Voraus schreiben (jetzt bezahlen) und dann weniger Arbeit haben, um die Innereien von employee.IsZipCodeValid() später zu ändern. Oder Sie können durch IsZipCodeValid tunneln, indem Sie

employee.GetAddress().GetZipCode().IsValid();
überall dort schreiben, wo Sie es im Code brauchen, aber später zahlen, wenn Sie sich entscheiden, Ihr Klassendesign in einer Weise zu ändern, die diesen Code bricht.

Sie können Ihr Gift wählen. ;)

+0

Dies ist wahrscheinlich die beste Antwort. Weil sie keine elegante Lösung für das Problem sind. – Arlukin

7

Sie vermissen die logische Verbindung:

class ZipCode 
{ 
public: 
bool IsValid(); 
} 

class Address { 
public: 
    ZipCode GetZipCode() const; 
    bool IsAddressValid(); 
    bool IsValid() {return GetZipCode()->IsValid() && IsAddressValid()); 
} 

class Employee { 
public: 
FullName GetName() const; 
Address GetAddress() const; 
bool IsEmployeeValid(); 
bool IsValid() {return GetAddress()->IseValid() && IsEmployeeValid()); 
PhoneNumber GetWorkPhone() const; 
} 

employee.IsValid(); 
+0

Sie müssten immer noch in 'ZipCode :: IsValid()' bohren. Sie rufen 'employee.IsValid()' auf und geben false zurück. OK, warum ist der Mitarbeiter nicht gültig? So rufen Sie 'employee.GetAddress(). IsValid()', und es gibt false zurück. OK, warum ist die Adresse nicht gültig? So rufen Sie 'employee.GetAddress(). GetZipCode(). IsValid()' und Sie sind zurück beim ursprünglichen Problem. – indiv

+0

Plus, dass Sie GetValue() auf ZipCode aufrufen möchten, um in einem Dialogfeld oder einer Webseite auszugeben. Das wird Ihnen das gleiche Problem geben. – Arlukin

+0

@indiv, wenn Sie dieses Beispiel auf face-Wert nehmen, dann ja, müssten Sie auf diese Weise einen Drilldown durchführen, aber Sie haben wahrscheinlich eine Methode, die dies für Sie tut und Fehlerdaten/-nachrichten für die Daten zurückgibt Eingabebildschirm Wenn dieser ungültige Zustand das Ergebnis schlechter Daten in der App ist, dann denke ich, dass die Antwort darin besteht, die Daten zu bereinigen, bevor sie in Ihr Modell injiziert werden. – Lazarus

0

Da zwischen der Employee-Klasse und der Postleitzahlvalidierung keine logische Verbindung besteht, könnten Sie die Postleitzahlvalidierung in die Address-Klasse einfügen, wo sie logischer zugehörig ist. Dann können Sie die Address-Klasse bitten, die Postleitzahl für Sie zu bestätigen.

class Address 
{ 
    public: 
     static IsZipValid(ZipCode zip) { return zip.isValid(); } 
}; 

Dann tun Sie

Address::IsZipValid(employee.GetAddress().GetZipCode()); 

Ich denke, das unter den Zwängen der logischen Verknüpfung und Gesetz von Demeter zufriedenstellend ist.

+0

Aber gewinnen Sie damit wirklich alles? Wahrscheinlich eine Frage des persönlichen Geschmacks, aber ich denke, dass mehr Punkte leichter zu lesen sind. Adresse :: IsZipValid (employee.GetAddress(). GetZipCode()); vs employee.GetAddress(). GetZipCode(). IsZipValid(); – Arlukin

+0

@Arlukin: Nein, ich glaube nicht, dass Sie etwas gewinnen. Ich habe gerade die gestellte Frage beantwortet. Demeter erlegt mir keine Gesetze auf, also würde ich es als Mitarbeiter implementieren. GetAddress(). GetZipCode.IsZipValid(). So fühlt es sich für mich natürlich an. – indiv

+0

@Arlukin, es geht nicht darum, zu gewinnen oder zu verlieren, es geht darum, ein Modell zu entwickeln, das Sinn macht. Wenn sich am Ende des Tages ein Weg für dich natürlicher anfühlt als ein anderer und du nicht Teil eines Teams bist (wenn du dann die Teamführung bekommst), dann gehe mit dem, was für dich sinnvoll ist. Ich bin sicher, wenn Sie zwei Programmierer in einen Raum bekommen, bekommen Sie sechs Meinungen darüber, wie man eine bestimmte Lösung programmiert;) – Lazarus