2009-07-04 4 views
2

Ich schreibe eine Reihe von kleinen, einfachen Anwendungen, die eine gemeinsame Struktur teilen und einige der gleichen Dinge auf die gleiche Art und Weise tun müssen (zB Protokollierung, Datenbankverbindung Setup, Umgebung Setup) und ich Ich suche nach einem Rat bei der Strukturierung der wiederverwendbaren Komponenten. Der Code ist in einer stark und statisch typisierten Sprache geschrieben (z. B. Java oder C#, ich musste dieses Problem in beiden lösen). Im Moment habe ich das:Architektur von einigen wiederverwendbaren Code

abstract class EmptyApp //this is the reusable bit 
{ 
    //various useful fields: loggers, db connections 

    abstract function body() 
    function run() 
    { 
     //do setup 
     this.body() 
     //do cleanup 
    } 
} 

class theApp extends EmptyApp //this is a given app 
{ 
    function body() 
    { 
     //do stuff using some fields from EmptyApp 
    } 

    function main() 
    { 
     theApp app = new theApp() 
     app.run() 
    } 
} 

Gibt es einen besseren Weg? Vielleicht wie folgt? Ich habe Probleme mit den Kompromissen mit einem Gewicht ...

abstract class EmptyApp 
{ 
    //various fields 
} 

class ReusableBits 
{ 
    static function doSetup(EmptyApp theApp) 

    static function doCleanup(EmptyApp theApp) 
} 

class theApp extends EmptyApp 
{ 
    function main() 
    { 
     ReusableBits.doSetup(this); 
     //do stuff using some fields from EmptyApp 
     ReusableBits.doCleanup(this); 
    } 
} 

Ein offensichtlicher Nachteil ist, dass mit der Option 2, der ‚Rahmen‘ nicht die App in einem Try-Catch-Block wickeln kann ...

Antwort

4

Ich habe immer die Wiederverwendung durch Zusammensetzung (Ihre zweite Option) eher als Vererbung (Ihre erste Option) bevorzugt.

Vererbung sollte nur verwendet werden, wenn eine Beziehung zwischen den Klassen und nicht für die Wiederverwendung von Code besteht.

Also für Ihr Beispiel würde ich mehrere ReusableBits Klassen haben, die jeweils eine Sache machen, die jede Anwendung als/wenn erforderlich nutzen.

Dadurch kann jede Anwendung die Teile Ihres Frameworks, die für diese spezifische Anwendung relevant sind, erneut verwenden, ohne gezwungen zu sein, alles zu nehmen, was den einzelnen Anwendungen mehr Freiheit gibt. Die Wiederverwendung durch Vererbung kann manchmal sehr restriktiv werden, wenn Sie in der Zukunft einige Anwendungen haben, die nicht genau in die Struktur passen, die Sie heute im Hinterkopf haben.

Sie werden auch das Komponententest und die testgetriebene Entwicklung viel einfacher finden, wenn Sie Ihr Framework in separate Dienstprogramme aufteilen.

0

Warum nicht den Framework-Aufruf auf Ihren anpassbaren Code machen? Ihr Client erstellt also ein Objekt und injiziert es in das Framework. Das Framework initialisiert, ruft setup() usw. auf und ruft dann den Clientcode auf. Nach Abschluss (oder sogar nach einer ausgelösten Ausnahme) ruft das Framework dann cleanup() auf und wird beendet.

So würde Ihr Kunde einfach eine Schnittstelle wie (in Java)

public interface ClientCode { 

    void runClientStuff(); // for the sake of argument 
} 

und der Framework-Code ist mit einer Umsetzung dieser konfiguriert implementieren und fordert runClientStuff() wann immer erforderlich.

Also Sie nicht Ableitung aus dem Anwendungsframework, sondern einfach eine Klasse, die einen bestimmten Vertrag entsprechen. Sie können das Anwendungssetup zur Laufzeit konfigurieren (z. B. welche Klasse der Client der App bereitstellt), da Sie nicht von der App abgeleitet werden und Ihre Abhängigkeit daher nicht statisch ist.

Die obige Schnittstelle kann erweitert werden, um mehrere Methoden zu haben, und die Anwendung kann die benötigten Methoden in verschiedenen Phasen des Lebenszyklus aufrufen (zB um ein clientspezifisches Setup/Cleanup bereitzustellen), aber das ist ein Beispiel für Feature Creep :-)

0

Denken Sie daran, Vererbung ist nur eine gute Wahl, wenn alle Objekte, die erben, den Code-Duo zu ihren Ähnlichkeiten wiederverwenden. oder wenn Sie möchten, dass Anrufer mit ihnen in derselben Spaltung interagieren können. Wenn das, was ich gerade erwähnt habe, auf dich zutrifft, dann ist es basierend auf meiner Erfahrung immer besser, die gemeinsame Logik in deiner Basis/abstrakten Klasse zu haben.

so würde ich Ihre Beispielanwendung in C# umschreiben.

Verwandte Themen