Während der Entwicklung neuer Funktionen in Ihrer Software ist dieser Prozess die beste Vorgehensweise
Wenn Sie die Route Nummer 2 wählen, wann entscheiden Sie, dass eine Schnittstelle benötigt wird?
Die Benutzeroberfläche wird angezeigt, wenn Sie allgemeine Funktionen aus mehreren Klassen umstrukturieren müssen.
Bis Sie mehrere Klassen mit gemeinsamen Funktionen haben, ist es schwer vorauszusehen, wie die Schnittstelle aussehen sollte.
Sobald Sie ein paar Klassen haben, ist es sehr viel einfacher, herauszufinden, was die Schnittstelle sein muss. Gehen Sie dann zurück und refactorieren Sie diese Klassen, um die neu entdeckte Schnittstelle richtig zu implementieren.
Einige Leute entwerfen viele Klassen auf Papier, um herauszufinden, was die Schnittstellen sein sollten. Speichert das Refactoring von echtem Code. Stattdessen müssen Sie Ihr Design umgestalten.
Trickfrage! Der Test kommt zuerst. Dann die Implementierung für den Test, die eine Klasse ist, die eine Schnittstelle bereits implementieren kann oder nicht. Ein Teil des Testdurchlaufs kann das Extrahieren einer Schnittstelle aus einer vorhandenen Klasse beinhalten, aber versuchen Sie nicht zu erraten, was Ihre Schnittstelle benötigen wird, bevor Sie etwas haben, das diese Schnittstelle benötigt.
Du wirst dich selbst verrückt machen, wenn du versuchst, das im Voraus herauszufinden - oder jedenfalls immer in meinen Tagen vor TDD. Entscheiden Sie, welche Funktionalität Ihre App benötigt, schreiben Sie einen Test und lassen Sie sich testen, was Sie mit Ihrem Code tun.
Ich stimme Brian Guthrie zu. Der Test kommt zuerst, weil er dein Design antreibt. Während dies normalerweise bedeutet, dass Sie mit einer konkreten Klasse enden (die, die Sie entwerfen, indem Sie ihr Verhalten in einer Reihe von Tests angeben), werden Abhängigkeiten normalerweise mittels Schnittstellen ausgedrückt (um Spott zu machen und dem Dependency Inversion-Prinzip ).
Das bedeutet oft, dass Sie die Schnittstellen haben, bevor Sie die Klassen haben, aber nur, weil Sie früher brauchen.
Ich gehe normalerweise mit der zweiten Option. Schreiben Sie später eine Klasse und extrahieren Sie die Schnittstelle. In der Regel ist der Grund für das Extrahieren einer Schnittstelle die Notwendigkeit einer zweiten Implementierung dieser Schnittstelle (oft als Nachahmung für Komponententests)
Ich würde sagen, dass die Schnittstellen an erster Stelle stehen, aber sie kommen auf, wenn Sie eine bestimmte Klasse / Methode entwickeln. Wenn Sie einen Punkt treffen, von dem Sie wissen, dass Sie von einer anderen Klasse / Methode abhängig sind, verwenden Sie eine Schnittstelle, um die Abhängigkeit hinzuzufügen und Ihren Code weiter zu schreiben. Gehen Sie dann zurück, nachdem Sie die aktuelle Komponente geschrieben und die Komponenten erstellt haben, die die benötigten Schnittstellen implementieren.
Alles hängt von der Situation ab ...
Wenn Sie in der Design-Phase wissen, dass Sie mehrere Klassen haben, die die gleiche "Gemeinsamkeit" haben, deren Implementierung jedoch unterschiedlich ist, dann steht die Oberfläche an erster Stelle.
Software ist jedoch organisch; Es entwickelt sich ständig weiter, so dass ich mir vorstellen kann, dass Sie in einigen Fällen eine Klasse haben und nach einiger Zeit eine Schnittstelle aus dieser Klasse extrahieren müssen.
Letztendlich sollte Ihre Entwurfsphase unabhängig von Ihrer Implementierungsphase sein. Bevor Sie mit dem Codieren beginnen, sollten Sie sich ein genaues Bild davon machen, wie die Interaktionen zwischen Ihren Klassen aussehen werden, und hoffentlich werden Ihre Schnittstellenentscheidungen daraus ersichtlich.
Wenn Sie jedoch bereits eine Klasse geschrieben haben und diese nun umgestalten müssen, um eine Schnittstelle zu haben, dann beachten Sie, dass die Schnittstelle einfach eine Reihe von Funktionen / Methoden auswählt, die einen gemeinsamen Zweck haben, der benötigt wird von mehr als einer Klasse. Wenn Sie feststellen, dass es einige nützliche Funktionen für Ihre anderen Klassen gibt, dann wären diese Methoden gute Kandidaten für eine Schnittstelle.
Ein weiterer Teil der Schnittstellen, der sie wirklich nützlich macht, ist, wenn Sie feststellen, dass es bestimmte Teile Ihrer Klasse gibt, die nicht privat sind, sondern von bestimmten anderen Objekten verborgen werden sollen. In diesem Fall können Sie die Funktionen übernehmen offenbaren wollen und sie zu einer Schnittstelle machen.
Ich stimme stark mit niemandem überein, der sagt, dass Sie nicht vorher entwerfen sollten. Codierer lieben es, direkt hinein zu springen, und manchmal ist ein Refactoring notwendig, aber eine starke Designphase wird später viel Zeit für das Refactoring einsparen.
Bei den meisten Klassen ist das Interface wirklich wichtig, da die Implementierung jederzeit geändert werden kann, aber sobald etwas in der Oberfläche bereitgestellt wird, ist es schwierig oder unmöglich, es zurückzuziehen. Für den Rest des Projekts ist die Schnittstelle entscheidend, und die Implementierung ist das Problem eines anderen.
Idealerweise werden die Hauptmerkmale der Schnittstelle vor jeder Implementierung spezifiziert. (Es ist eine gute Idee, auch Tests im Voraus zu entwickeln.) Die Details können sich weiterentwickeln, aber alle Änderungen an der Schnittstelle sollten auf dem basieren, was andere Klassen und Routinen benötigen, und nicht auf Artefakten der Implementierung. Die Implementierung sollte immer von der Schnittstelle bestimmt werden, nicht umgekehrt.
(Da dies eine sprachunabhängige Frage ist, gehe ich davon aus, dass es sich bei der diskutierten "Schnittstelle" um die öffentliche Funktionalität der Klasse handelt und nicht etwa um Java als Ersatz für abstrakte C ++ - Klassen. In C ++ wäre das so die Teile der Klassendefinition als "public" markiert.)
Im Allgemeinen brauchen Sie keine Schnittstelle, es sei denn, Sie haben mehrere Klassen im Auge, die es implementieren werden. Also, die Schnittstelle würde zuerst kommen.
Die Klasse sollte zuerst kommen.
Ein schönes Design kann nur bestimmt werden, um schön zu sein, wenn es dem Tiegel der Veränderung unterzogen wird. Woher wissen Sie, ob Ihre Schnittstellen dem Test der Zeit standhalten, wenn sie nicht von Anfang an durch Code gefälscht wurden?
Ich möchte zwei verschiedene Ansichten darüber, welche Schnittstellen sind:
In beiden Fällen entwerfen Sie jedoch zuerst und dann programmieren Sie.
Für ein neues System würde ich erwarten, dass zuerst Kandidatenschnittstellen identifiziert werden, die später von Klassen implementiert werden. Für ein vorhandenes System wird eine Schnittstelle zu vorhandenen Klassen entwickelt, wenn Sie in Ihrem System eine wichtige Entität oder einen Variationspunkt entdecken, an dem es zuvor nicht so wichtig war oder an dem Sie zuvor keinen Variationspunkt angeben mussten.
Was kommt zuerst? Die Notwendigkeit für ein Feature oder die Implementierung eines Features?
In meinem eigenen Workflow kommt das Interface zuerst spontan. Wenn ein Teil meines Projekts ein neues Feature benötigt, ist es so aufgebaut, wie ich es verwenden möchte, d. H. Seine Schnittstelle. Dann folgt die Implementierung.
Auf diese Weise enthält die Implementierung nur das, was tatsächlich benötigt wird, und es wird keine Zeit damit verschwendet, ein glänzend nutzloses Stück Code zu überarbeiten.
Schnittstellen entwickeln sich im Laufe der Zeit sehr schlecht. Wann immer Sie die Schnittstelle ändern, brechen Sie den Vertrag. Alle Klassen, die die Schnittstelle implementieren, müssen refaktoriert werden. Um rückwärtskompatibel zu bleiben, werden Entwickler kreativ und gestalten IFoo2 über IFoo. Dies wird mit der Zeit zu einem Alptraum.
Beachten Sie Folgendes: Definieren Sie lieber Klassen über Schnittstellen. Verwenden Sie Schnittstellen, wenn Sie eine polymorphe Hierarchie von Werttypen bereitstellen möchten. Eine andere Art der Verwendung von Schnittstellen besteht darin, einen ähnlichen Effekt wie bei der Mehrfachvererbung zu erzielen.
Tags und Links language-agnostic design oop