Frage

Ich schrieb vor kurzem eine Klasse, die B-Spline-Kurven macht. Diese Kurven werden durch eine Reihe von Kontrollpunkten definiert ist. Ursprünglich hatte ich gedacht acht Kontrollpunkte zu verwenden, so habe ich eine Konstante der Klasse, etwa so:

class Curve
{
   public:
      static const int CONTROL_POINT_COUNT = 8;
};

Jetzt möchte ich diese Klasse zu erweitern, eine beliebige Menge von Kontrollpunkten zu ermöglichen. Deshalb möchte ich dies ändern:

class Curve
{
   public:
      int getControlPointCount() {return _controlPointCount;}
};

Die Frage ist, ob es nicht besser ist Konstanten in Methoden zu speichern zu beginnen, zu erleichtern Anpassungsfähigkeit. Mit anderen Worten, es wird nicht besser gestartet somit haben:

class Curve
{
   public:
      int getControlPointCount() {return 8;}
};

Der Vorteil dabei ist, dass ich nur ein Symbol in dem Verfahren in Frage geändert haben könnte, anstatt um Konstanten der Bewegung etc.

Ist das eine gute Praxis oder ein schlechter?

War es hilfreich?

Lösung

Normalerweise möglichst wenigen Kupplungen manuell wie möglich Ich bin für die Aufrechterhaltung.

Die Zahl der Kontrollpunkte in der Kurve ist, na ja, die Zahl der Kontrollpunkte in der Kurve. Es ist keine unabhängige Variable, die nach Belieben eingestellt werden können.

Also ich würde in der Regel eine konstante Standardcontainer Referenz aussetzen:

class Curve
{   
    private:
        std::vector<Point>& _controlPoints;

    public:      
        Curve ( const std::vector<Point>& controlPoints) : _controlPoints(controlPoints)
        {
        }

        const std::vector<Point>& getControlPoints ()
        {
            return _controlPoints;
        }
};

Und wenn Sie wissen wollen, wie viele Kontrollpunkte, dann curve.getControlPoints().size() verwenden. Ich würde vermuten, dass in den meisten der Anwendungsfälle Sie die Punkte wollen würde sowie die Zählung sowieso, und durch einen Standard-Container Belichten können Sie die Standard-Bibliothek des Iterators Idiome und integrierten Algorithmen verwenden, sondern die Zählung immer und ruft eine Funktion wie getControlPointWithIndex in einer Schleife.

Wenn es wirklich nichts anderes in der Kurve Klasse, ich könnte sogar so weit gehen:

typedef std::vector<Point> Curve;

(oft eine Kurve wird sich nicht machen, als ein Renderer Klasse Details über die Rendering-Pipeline haben kann, eine Kurve als rein geometrischen Artefakt verlassen)

Andere Tipps

int getControlPointCount() {return _controlPointCount;}

Dies ist ein Accessor. eine konst statisch für eine Accessor Swapping ist nicht wirklich ein Gewinn als litb hingewiesen hat. Was Sie brauchen, um zukunftssicher ist wahrscheinlich ein Paar von Accessor und Mutator wirklich.

int getControlPointCount() {return _controlPointCount;} // accessor

ich auch in einem Design-const für die Accessor werfen würde und machen es:

int getControlPointCount() const {return _controlPointCount;} // accessor

und die entsprechend:

void setControlPointCount(int cpc) { _controlPointCount = cpc;} //mutator

Nun ist der große Unterschied mit einem statischen Objekt, dass die Steuerpunktzahl ist nicht länger ein Klasse-Level-Attribut, sondern eine Instanz-Ebene ein. Dies ist eine Designänderung . Wünschen Sie es auf diese Weise?

Nit: Ihre Klassenstufe statische Zählung public und daher nicht einen Accessor braucht

.

Um besser auf Ihre Frage zu beantworten, sollte man auch wissen, wie die controlPointCount Variable gesetzt ist. Ist es außerhalb von Ihrer Klasse festgelegt? In diesem Fall sollten Sie auch einen Setter definieren. Oder die Curve-Klasse ist die alleinige Verantwortung dafür einstellen? Ist es nur auf der Kompilierung oder auch zur Laufzeit festgelegt.

Wie auch immer, vermeidet eine magische Zahl auch in dieser Form:

int getControlPointCount() {return 8;}

Das ist besser:

int getControlPointCount() {return CONTROL_POINT_COUNT;}

Ein Verfahren hat den Vorteil, dass Sie die interne Implementierung ändern können (mit einem konstanten Wert, aus einer Konfigurationsdatei zu lesen, den Wert dynamisch ändern), ohne dass die außerhalb der Klasse zu beeinflussen.

class Curve
{   
    private:
        int _controlPointCount;

        void setControlPointCount(int cpc_arg)
        {
            _controlPointCount = cpc_arg;
        }

    public:      
        curve()
        {
            _controlPointCount = 8;
        }

        int getControlPointCount() const
        {
            return _controlPointCount;
        }
};

Ich werde einen Code wie folgt, mit Set-Funktion in privaten schaffen, so dass kein Körper mit Kontrollpunkt Zahl spielen kann, bis wir in der nächsten Phase der development..where bewegen wir Anfang aktualisieren die Kontrollpunkt Zahl aktualisieren an Laufzeit. zu dieser Zeit, können wir diese Set-Methode von privaten zu öffentlichen Rahmen bewegen.

Während die Frage zu verstehen, ich habe eine Reihe von konzeptionellen Problemen mit dem Beispiel:

  • Was ist der Rückgabewert für getControlPointCount() wenn die Anzahl der Kontrollpunkte nicht beschränkt ist?
    • Ist es MAXINT?
    • Ist es die aktuelle Anzahl der Kontrollpunkte auf der Kurve (also die Logik zu brechen, der sagt, dass dies die größtmögliche Anzahl von Punkten?)
  • Was passiert, wenn Sie tatsächlich eine Kurve mit MAXINT Punkten zu erstellen versuchen? Sie werden schließlich über genügend Arbeitsspeicher ausgeführt.

Die Schnittstelle selbst scheint mir problematisch. Wie andere Standard-Collection-Klassen, sollte die Klasse ihre Beschränkung auf die Anzahl von Punkten haben gekapselt und seine AddControlPoint() sollte einen Fehler zurückgegeben, wenn eine Beschränkung auf Größe, Speicher oder jede andere Verletzung aufgetreten ist.

Wie für die spezifische Antwort, ich bin einverstanden mit kgiannakakis: Mitglied Funktion mehr Flexibilität ermöglicht

.

Ich neige dazu, Konfiguration zu verwenden + Konstante (Standardwert) für alle ‚stabil‘ Werte durch die Ausführung des Programms. Mit einfachen Konstanten für Werte, die nicht ändern können (360 Grad -> 2 pi Radian, 60 Sekunden -> 1 Minute) oder zu ändern, die brechen würde den Laufcode (Minimal- / Maximalwerte für Algorithmen, die sie instabil machen)

.

Sie sind mit einigen verschiedenen Designfragen. Zunächst müssen Sie wissen, ob die Anzahl der Kontrollpunkte ist eine Klasse oder Instanz Pegelwert. Dann ob es sich um eine Konstante auf jedem der beiden Ebenen.

Wenn alle Kurven die gleiche Anzahl von Kontrollpunkten in Ihrer Anwendung teilen müssen, dann ist es eine Klasse Ebene (statisch) Wert. Wenn verschiedene Kurven unterschiedliche Anzahl von Kontrollpunkten haben kann, dann ist es kein Klassenpegelwert, sondern eine Instanz-Ebene ein.

In diesem Fall, wenn die Anzahl der Kontrollpunkt wird während der gesamten Lebensdauer der Kurve konstant sein, dann ist es eine Instanzebene konstant, wenn es dann ändern kann es auf dieser Ebene nicht konstant ist, auch nicht.

// Assuming that different curves can have different 
// number of control points, but that the value cannot 
// change dynamically for a curve.
class Curve
{
public:
   explicit Curve( int control_points )
      : control_points_( control_points )
   {}
   // ...
private:
   const int control_points_;
};

namespace constant
{
   const int spline_control_points = 8;
}
class Config
{
public:
   Config();
   void readFile( std::string const & file );

   // returns the configured value for SplineControlPoints or
   // constant::spline_control_points if the option does not 
   // appear in config.
   int getSplineControlPoints() const;
};

int main()
{
   Config config;
   config.readFile( "~/.configuration" ); // read config

   Curve c( config.getSplineControlPoints() );
}

Für Integral-Typen bin ich usualy mit:

class Curve
{
   public:
      enum 
      {
          CONTROL_POINT_COUNT = 8
      };
};

Wenn Konstante muss nicht für alle Einheiten außer Klassenimplementierung ich Konstanten in * CPP-Datei deklariert werden.

namespace
{
const int CONTROL_POINT_COUNT = 8;
}

In der Regel alle Ihre Daten sollten über Getter und Setter privat und zugänglich sein. Andernfalls verletzen Sie Kapselung. Das heißt, wenn Sie die zugrunde liegenden Daten aussetzen sperren Sie sich und Ihre Klasse in eine bestimmte Darstellung dieser zugrunde liegenden Daten.

In diesem speziellen Fall würde ich das so etwas wie die folgenden getan haben denke ich:

class Curve
{

   protected:

      int getControlPointCount() {return _controlPointCount;}
      int setControlPointCount(int c) { _controlPointCount = c; }

   private:

      static int _controlPointCount = 0;
};

Konstanten im Allgemeinen sollte sie nicht in Methoden definiert werden. Das Beispiel Sie die Wahl hat zwei einzigartige Eigenschaften. Erstens ist es ein Getter; eine zweite int ist der Typ zurückgeführt wird. Aber der Punkt der Definition von Konstanten ist sie mehr als einmal zu verwenden, und in der Lage sein auf eine bequeme Art, um sie zu verweisen. Die Eingabe „8“ im Gegensatz zu „controlPointCount“ können Sie Zeit sparen, und scheinen keine Wartungskosten entstehen, aber dies wird normalerweise nicht wahr sein, wenn Sie immer Konstanten innerhalb Methoden definieren.

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