4 Stimmen

Modularität: Schnittstellen verwenden oder nicht?

Seit ein paar Jahren scheint der gesunde Menschenverstand zu diktieren, dass es besser ist, gegen Schnittstellen zu programmieren als gegen Implementierungen. Für High-Level-Code scheint dies in der Tat logisch zu sein. Wenn ich z.B. einen komplexen Solver in meiner Anwendung habe, scheint es besser zu sein, so etwas wie das hier zu haben:

ISolver *solver = solverFactory.getSolver();
solver->solve(inputdata);

Anstatt

Solver solver;
solver.solve(inputdata);

Im ersten Code ist es auch einfacher, den Solver zu mocken und somit einen Unit-Test durchzuführen.

Aber meine Frage ist: auf welcher Ebene macht es keinen Sinn mehr, Schnittstelle zu verwenden. Wenn ich z.B. eine ComplexNumber Klasse (oder String Klasse, oder was auch immer) in meiner Anwendung habe, dann schreibe ich dies:

IComplexNumber *complexNumber = complexNumberFactory.create(1,2);   // 1+2i

Es scheint viel komplexer zu sein (vor allem hinsichtlich der Leistung) als das Schreiben:

ComplexNumber complexNumber(1,2);   // 1+2i

Welche Elemente sind also wichtig, um zu entscheiden, ob etwas hinter eine Schnittstelle gestellt werden sollte und wann es nicht hinter eine Schnittstelle gestellt werden sollte?

3voto

Michael Anderson Punkte 65535

Ein Grund für den Wechsel zu einer Schnittstelle ist, dass sie die Dinge vereinfacht oder die Kopplung reduziert. (Dafür ist eine Schnittstelle da).

Ein Grund, von einer Schnittstelle abzurücken, ist, wenn sie die Dinge komplizierter macht oder die Leistung beeinträchtigt (aber ein Profil, um sicher zu sein). Ich würde argumentieren, dass Ihre IComplexNumber-Klasse tatsächlich die Klassenhierarchie komplexer macht, es sei denn, Sie eine MockComplexNumber einführen, aber ich bezweifle, dass eine solche Klasse nützlich sein würde... und es wird wahrscheinlich machen Dinge langsamer, aber ich würde das messen.

Aber denken Sie nicht, dass Sie alles auf die eine Art machen müssen oder dass Ihre Entscheidungen in Stein gemeißelt sind. Es ist ziemlich einfach, über eine Schnittstelle zu konvertieren.

1voto

WW. Punkte 22847

Wenn Sie Ihre Klassen in "Dienst"- und "Wert"-Klassen unterteilen, je nachdem, welche Rolle sie spielen, dann ist die Antwort einfach. Verwenden Sie nur Schnittstellen für Dienstklassen. In Ihrer Frage ist der "Solver" ein Dienst und die "komplexe Zahl" ein Wert.

Wertklassen sollten mit new() einfach zu erstellen sein, da sie im Konstruktor nur Basistypen und andere Wertklassen akzeptieren. Wertklassen sind nicht zum Spotten geeignet, da man das echte Ding verwenden kann.

Es kann nützlich sein, Dienstklassen nachzubilden, und Sie möchten vielleicht mehrere Implementierungen. Ihre solverFactory könnte einen naiveSolver, einen lookupSolver, einen geneticSolver, einen mockSolver usw. zurückgeben. Hier ist eine Schnittstelle nützlich.

-2voto

mmmmmm Punkte 31394

Bei C++ spielt das keine Rolle, da C++ über Mehrfachvererbung verfügt und eine Schnittstelle eine abstrakte Klasse ist, zu der man eine Implementierung hinzufügen kann. Ich habe festgestellt, dass Schnittstellen am häufigsten in Java und C# verwendet werden, wo es nur eine Vererbung gibt und wenn eine Klasse mehrere Dinge implementieren soll, kann nur eine Klasse eine abstrakte Klasse sein, die anderen müssen Schnittstellen sein.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X