Obwohl dies eine allgemeine Frage ist, ist sie auch spezifisch für ein Problem, auf das ich momentan stoße. Ich habe derzeit eine in meiner Lösung angegebene Schnittstelle namens
public interface IContextProvider
{
IDataContext { get; set; }
IAreaContext { get; set; }
}
Diese Schnittstelle wird oft im gesamten Programm verwendet und daher habe ich einfachen Zugriff auf die Objekte, die ich benötige. Auf einer relativ niedrigen Ebene eines Teils meines Programms benötige ich jedoch Zugriff auf eine andere Klasse, die IAreaContext verwendet und einige Operationen außerhalb dieser Klasse ausführt . Deshalb habe ich eine andere Factory-Oberfläche erstellt, die folgende Bezeichnung hat:
public interface IEventContextFactory
{
IEventContext CreateEventContext(int eventId);
}
Ich habe eine Klasse, die den IContextProvider implementiert und mit NinJect injiziert wird. Das Problem, das ich habe, ist, dass der Bereich, in dem ich diesen IEventContextFactory verwenden muss, nur Zugriff auf den IContextProvider hat und selbst eine andere Klasse verwendet, die diese neue Schnittstelle benötigt. Ich möchte diese Implementierung von IEventContextFactory nicht auf der niedrigen Ebene instanziieren müssen und möchte lieber durchgehend mit der IEventContextFactory- Schnittstelle arbeiten. Ich möchte jedoch auch keinen weiteren Parameter über die Konstruktoren einfügen müssen, nur um ihn an die Klasse weiterzuleiten, die ihn benötigt, d. H
// example of problem
public class MyClass
{
public MyClass(IContextProvider context, IEventContextFactory event)
{
_context = context;
_event = event;
}
public void DoSomething()
{
// the only place _event is used in the class is to pass it through
var myClass = new MyChildClass(_event);
myClass.PerformCalculation();
}
}
Meine Hauptfrage ist also, ob dies akzeptabel ist oder ob es überhaupt üblich ist, so etwas zu tun (Interface erweitere ein anderes Interface):
public interface IContextProvider : IEventContextFactory
oder sollte ich bessere Alternativen in Betracht ziehen, um das zu erreichen, was ich brauche? Wenn ich nicht genügend Informationen zur Verfügung gestellt habe, um Vorschläge zu machen, lass es mich wissen und ich kann mehr liefern.
quelle
Antworten:
Während Interfaces nur das Verhalten ohne Implementierung beschreiben, können sie dennoch an Vererbungshierarchien teilnehmen. Stellen Sie sich beispielsweise vor, Sie hätten die gemeinsame Idee von a
Collection
. Diese Schnittstelle bietet einige Gemeinsamkeiten für alle Auflistungen, z. B. eine Methode zum Durchlaufen der Member. Dann können Sie sich einige spezifischere Sammlungen von Objekten wie aList
oder a überlegenSet
. Jeder von diesen erbt alle Verhaltensanforderungen von aCollection
, fügt jedoch zusätzliche Anforderungen hinzu, die für diesen bestimmten Sammlungstyp spezifisch sind.Wann immer es sinnvoll ist, eine Vererbungshierarchie für Schnittstellen zu erstellen, sollten Sie dies tun. Wenn zwei Schnittstellen immer zusammen gefunden werden, sollten sie wahrscheinlich zusammengeführt werden.
quelle
Ja, aber nur wenn es Sinn macht. Stellen Sie sich die folgenden Fragen, und wenn eine oder mehrere zutreffen, ist es akzeptabel, eine Schnittstelle von einer anderen zu erben.
In Ihrem Beispiel antwortet es meiner Meinung nach auf keines von diesen mit Ja. Sie können es besser als eine andere Eigenschaft hinzufügen:
quelle
IContextProvider
Erweiterung vornehmen . Wenn Sie es als eine Eigenschaft hinzufügen, sagen Sie, dass a ein hat, aber die Implementierungsdetails nicht wirklich kennt.IEventContextFactory
ContextProvider
ContextProvider
IEventContextFactory
Ja, es ist in Ordnung, eine Schnittstelle von einer anderen zu erweitern.
Die Frage, ob es in einem bestimmten Fall das Richtige ist, hängt davon ab, ob es eine wahre "Ist-Ein" -Beziehung zwischen den beiden gibt.
Was ist für eine gültige "is-a" -Beziehung erforderlich?
Erstens muss es einen echten Unterschied zwischen den beiden Schnittstellen geben, dh es muss Instanzen geben, die die übergeordnete Schnittstelle implementieren, nicht jedoch die untergeordnete Schnittstelle. Wenn es keine Instanzen gibt, die nicht beide Schnittstellen implementieren, sollten die beiden Schnittstellen stattdessen zusammengeführt werden.
Zweitens muss es so sein, dass jede Instanz der untergeordneten Schnittstelle unbedingt eine Instanz der übergeordneten Schnittstelle sein muss: Es gibt keine (sinnvolle) Logik, unter der Sie eine Instanz der untergeordneten Schnittstelle erstellen würden, deren Instanz keinen Sinn ergeben würde die übergeordnete Schnittstelle.
Wenn beides zutrifft, ist die Vererbung die richtige Beziehung für die beiden Schnittstellen.
quelle
IReadOnlyList
nützlich sein, auch wenn alle meine Listenklassen implementierenIList
(von denen abgeleitet istIReadOnlyList
).Ist die eine Schnittstelle immer die andere benötigen / bereitstellen möchte, fahren Sie fort. Ich habe dies in einigen Fällen gesehen
IDisposible
, die Sinn ergeben haben. Im Allgemeinen sollten Sie jedoch sicherstellen, dass sich mindestens eine der Schnittstellen eher wie eine Eigenschaft als eine Verantwortung verhält.Für Ihr Beispiel ist es nicht klar. Wenn beide immer zusammen sind, erstellen Sie einfach eine Schnittstelle. Wenn einer immer den anderen braucht, würde ich mir Sorgen machen über die Art der Vererbung "X und 1", die sehr oft zu mehreren Verantwortlichkeiten und / oder anderen undichten Abstraktionsproblemen führt.
quelle