Frage

Okay, hier ist also ein Problem in Ich renne.

Ich habe einige Klassen in meiner Anwendung, die Methoden, die eine Datenbankverbindung benötigen. Ich bin zwischen zwei verschiedenen Wegen zerrissen die Klassen zu entwerfen, welche beide um Dependency Injection zentriert sind:

  1. eine Eigenschaft für die Verbindung bereitstellen, die von dem Anrufer vor dem Methodenaufruf gesetzt wird. Dies hat einige Nachteile.

    • Jede Methode auf der Verbindungseigenschaft verlassen hat diese Eigenschaft zu überprüfen, um sicherzustellen, dass es nicht null ist, es ist offen und nicht an einer Transaktion beteiligt, wenn diese den Vorgang verhunzt los ist.

    • Wenn die Verbindungseigenschaft unerwartet geschlossen wird, werden alle Methoden müssen entweder (1) werfen eine Ausnahme oder (2.) zwingen sie zu öffnen. Je nach dem Grad der Robustheit, die Sie wollen, ist entweder Fall angemessen. (Beachten Sie, dass dies unterscheidet sich von einer Verbindung, die sich auf ein Verfahren, dass übergeben wird der Verweis auf die Verbindung für die Lebensdauer des Objekts vorhanden ist, nicht nur für die gesamte Lebensdauer des Methodenaufruf. Folglich ist die Volatilität der Verbindung scheint höher zu mir.)

    • eine Connection Eigenschaft Bereitstellung scheint (mir jedenfalls) für eine entsprechende Transaction Eigenschaft zu schreien. Dies schafft zusätzlichen Aufwand in der Dokumentation, da Sie es ziemlich offensichtlich machen müßten, wenn die Transaktion verwendet wurde, und wenn es nicht ist.

    Auf der anderen Seite scheint Microsoft das ganze Set-and-invoke Paradigma zu begünstigen.

  2. die Verbindung erfordern, um die Methode übergeben als Argument werden. Dies hat einige Vorteile und Nachteile:

    • Die Parameterliste ist natürlich größer. Das ist lästig für mich in erster Linie an der Stelle des Anrufs.

    • Während eine Verbindung (und eine Transaktion) noch vor validiert werden müssen, verwenden, besteht der Hinweis auf sie nur für die Dauer des Methodenaufrufs.

    • Der Punkt, der Anruf ist jedoch ganz klar. Es ist sehr offensichtlich, dass Sie muß die Verbindung zur Verfügung stellen, und dass das Verfahren nicht automatisch einen hinter dem Rücken erschaffen.

    • Wenn eine Methode keine Transaktion (zum Beispiel ein Verfahren, das nur Daten aus der Datenbank abgerufen) benötigen, wird keine Transaktion erforderlich. Es gibt keinen Mangel an Klarheit wegen der Methodensignatur.

    • Wenn eine Methode eine Transaktion erfordert, ist es sehr klar aufgrund der Methodensignatur. Auch hier gibt es keinen Mangel an Klarheit.

    • Da die Klasse keine Connection oder eine Transaction Eigenschaft aussetzen, gibt es keine Möglichkeit, Anrufer versuchen, durch sie aufschlüsseln, um ihre Eigenschaften und Methoden, damit das Gesetz des Demeter erzwingen.

Ich weiß, es ist eine Menge. Aber auf der einen Seite gibt es die Microsoft Way: Geben Sie Eigenschaften, lassen Sie den Anrufer setzen die Eigenschaften, und dann Methoden aufrufen. Auf diese Weise müssen Sie keine komplizierten Konstrukteuren oder Fabrikmethoden und dergleichen erstellen. Vermeiden Sie auch Methoden mit vielen Argumenten.

Dann ist da noch die Tatsache, dass, wenn ich diese beiden Eigenschaften auf meinen Objekten aussetzen, werden sie neigen dazu, die Verbraucher zu ermutigen, in schändlicher Weise zu nutzen. (Nicht, dass ich dafür verantwortlich, aber trotzdem.) Aber ich will einfach nicht wirklich beschissen Code schreiben.

Wenn Sie in meinen Schuhen sind, was würden Sie tun?

War es hilfreich?

Lösung

Hier ist ein drittes Muster zu beachten:

  • Erstellen Sie eine Klasse namens ConnectionScope, die den Zugriff auf eine Verbindung
  • bietet
  • Jede Klasse, jederzeit kann ein ConnectionScope erstellen
  • hat ConnectionScope eine Eigenschaft namens Verbindung, die immer eine gültige Verbindung zurück
  • Jede (und jede) ConnectionScope ermöglicht den Zugriff auf die gleichen Verbindungsobjekt zugrunde liegen (innerhalb eines gewissen Umfang, vielleicht im selben Thread oder Prozess)

Sie sind dann frei, dass die Connection-Eigenschaft zu implementieren, wie Sie wollen, und Ihre Klassen haben keine Eigenschaft, die festgelegt werden muss, noch ist die Verbindung ein Parameter, noch müssen sie über das Öffnen oder Schließen von Verbindungen sorgen.

Weitere Informationen:

  • In C #, würde ich empfehlen ConnectionScope implementieren IDisposable, auf diese Weise Ihre Klassen-Code wie „verwenden (var Umfang = new ConnectionScope ())“ schreiben können, und dann kann ConnectionScope die Verbindung frei (falls zutreffend), wenn es zerstört wird
  • Wenn Sie sich auf eine Verbindung pro Thread begrenzen (oder Prozess), dann können Sie ganz einfach die Verbindungszeichenfolge in einem [thread] statische Variable in ConnectionScope gesetzt
  • Sie können dann mit Referenzzählung um sicherzustellen, dass Ihre einzige Verbindung wiederverwendet wird, wenn seine bereits geöffnet und Verbindungen freigesetzt werden, wenn niemand sie wird mit

Aktualisiert: Hier ist etwas vereinfachte Beispielcode:

public class ConnectionScope : IDisposable
{
   private static Connection m_Connection;
   private static int m_ReferenceCount;

   public Connection Connection
   {
      get
      {
          return m_Connection;
      }
   }

   public ConnectionScope()
   {
      if ( m_Connection == null )
      {
          m_Connection = OpenConnection();
      }
      m_ReferenceCount++;
   }

   public void Dispose()
   {
      m_ReferenceCount--;
      if ( m_ReferenceCount == 0 )
      {
         m_Connection.Dispose();
         m_Connection = null;
      }
   }
}

Beispiel-Code, wie man (any) der Klassen würde verwenden:

using ( var scope = new ConnectionScope() )
{
   scope.Connection.ExecuteCommand( ... )
}

Andere Tipps

Ich würde die letztere Methode bevorzugen. Es klingt wie Ihre Klassen die Datenbankverbindung als eine Leitung zu der Persistenz-Schicht verwendet werden. den Anrufer Pass in der Datenbankverbindung zu machen macht deutlich, dass dies der Fall ist. Wenn die Verbindung / Transaktion als eine Eigenschaft des Objekts vertreten waren, dann sind die Dinge nicht so klar, und alle der Eigentums- und Lebensdauer Fragen kommen. Besser, sie von Anfang an zu vermeiden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top