2008-09-30 7 views
10

Ich frage mich, wie (un) üblich es ist, einen Algorithmus in eine Klasse zu kapseln? Genauer gesagt, statt eine Reihe von getrennten Funktionen, die zwischen einander gemeinsame Parameter weiter:Einen Algorithmus in eine Klasse einkapseln

void f(int common1, int param1, int *out1); 
void g(int common1, int common2, int param1, int *out2) 
{ 
    f(common1, param1, ..); 
} 

gemeinsame Parameter in eine Klasse zu kapseln und im Konstruktor alle Arbeit tun:

struct Algo 
{ 
    int common1; 
    int common2; 

    Algo(int common1, int common2, int param) 
    { // do most of the work } 

    void f(int param1, int *out1); 
    void g(int param1, int *out2); 
}; 

Es scheint sehr praktisch, gemeinsame Parameter und Zwischenergebnisse nicht über Funktionsargumente weiterleiten zu müssen. Aber ich habe nicht gesehen, dass dieses "Muster" weit verbreitet ist. Was sind die möglichen Nachteile?

Antwort

5

Es ist keine schlechte Strategie überhaupt. In der Tat, wenn Sie die Möglichkeit, in Ihrer Sprache haben (die Sie in C++ zu tun) eine Art der abstrakten Oberklasse zu definieren, die eine undurchsichtige Schnittstelle auf die zugrunde liegende Funktionalität definiert, können Sie verschiedene Algorithmen in und aus zur Laufzeit tauschen (man denken Sortieralgorithmen, beispielsweise). Wenn Ihre gewählte Sprache eine Reflexion hat, können Sie sogar Code haben, der unendlich erweiterbar ist, was das Laden und Verwenden von Algorithmen ermöglicht, die möglicherweise gar nicht existierten, als der Benutzer dieser Algorithmen geschrieben wurde. Dies ermöglicht es Ihnen auch, Ihre anderen funktionalen Klassen und algorithmischen Klassen lose zu koppeln, was beim Refactoring hilfreich ist und Ihre geistige Gesundheit bei der Arbeit an großen Projekten intakt hält.

Natürlich, wann immer Sie beginnen, eine komplexe Klassenstruktur zu erstellen, wird es eine zusätzliche Architektur - und damit Code - geben, die aufgebaut und gewartet werden muss. Meiner Meinung nach überwiegen die Vorteile auf lange Sicht jedoch diese kleinen Unannehmlichkeiten.

Ein letzter Vorschlag: nicht tun Sie Ihre Arbeit im Konstruktor. Konstruktoren sollten nur verwendet werden, um die interne Struktur einer Klasse auf angemessene Standardwerte zu initialisieren. Ja, dies kann den Aufruf anderer Methoden zum Beenden der Initialisierung beinhalten, aber die Initialisierung ist nicht Operation. Die beiden sollten getrennt sein, selbst wenn es einen weiteren Aufruf in Ihrem Code erfordert, um den bestimmten Algorithmus auszuführen, nach dem Sie gesucht haben.

0

Wenn Sie jemals beide Methoden mit den Konstruktorparametern aufrufen müssten, würde ich es tun.

Wenn Sie nie beide Methoden mit den gleichen Parametern aufrufen müssten, würde ich nicht.

5

Es gibt ein Designmuster, das das Problem anspricht; Es heißt "Strategy Design Pattern" - Sie können einige gute Informationen darüber finden here.

Das Schöne an "Strategy" ist, dass man damit eine Familie von Algorithmen definieren und diese dann austauschbar verwenden kann, ohne die Clients, die die Algorithmen verwenden, modifizieren zu müssen.

1

Ich erstelle normalerweise einen Funktor oder Function Object, um meine Algorithmen einzukapseln.

Normalerweise verwende ich die folgende Vorlage

class MyFunctor { 
    public: 
     MyFunctor(/* List of Parameters */); 
     bool execute(); 
    private: 
     /* Local storage for parameters and intermediary data structures */ 
} 

Dann habe ich meine functors diese Weise verwendet:

bool success = MyFunctor(/*Parameter*/).execute(); 
+0

Ich würde erwarten, dass ein Funktionsobjekt mit operator() ausgeführt wird –

1

Vielleicht ist ein besserer Ansatz (es sei denn, ich verpasse etwas), den Algorithmus in eine Klasse einzufügen und durch einen Methodenaufruf ausführen zu lassen.Sie können entweder alle Parameter über einen Konstruktor an öffentliche Eigenschaften übergeben oder eine Struktur erstellen, die alle Parameter kapselt, die an eine Klasse übergeben werden, die den Algorithmus enthält. Aber normalerweise ist es keine gute Idee, Dinge im Konstruktor so auszuführen. In erster Linie, weil es nicht intuitiv ist.

public class MyFooConfigurator 
{ 
    public MyFooConfigurator(string Param1, int, Param2) //Etc... 
    { 
     //Set all the internal properties here 
     //Another option would also be to expose public properties that the user could 
     //set from outside, or you could create a struct that ecapsulates all the 
     //parameters. 
     _Param1 = Param1; //etc... 
    } 

    Public ConfigureFoo() 
    { 
     If(!FooIsConfigured) 
      return; 
     Else 
      //Process algorithm here. 
    } 
} 
2

Könnte Ihre Frage ganz allgemein wie, formuliert werden, „wie verwenden wir objektorientiertes Design, wenn die Hauptidee der Software nur ein Algorithmus ausgeführt wird?“

In diesem Fall denke ich, dass ein Design wie Sie angeboten ein guter erster Schritt ist, aber diese Dinge sind oft problemabhängig.

Ich denke, ein gutes allgemeines Design ist wie das, was Sie dort haben. . .

Dann lassen Sie das mit der main() oder Ihrer GUI interagieren, wie Sie wollen.

Verwandte Themen