هل من الأفضل تخزين ثوابت الفصل في أعضاء البيانات أم في الأساليب؟

StackOverflow https://stackoverflow.com/questions/647648

  •  22-07-2019
  •  | 
  •  

سؤال

لقد كتبت مؤخرًا فصلًا يعرض منحنيات B-spline.يتم تعريف هذه المنحنيات من خلال عدد من نقاط التحكم.في الأصل، كنت أنوي استخدام ثماني نقاط تحكم، لذلك أضفت ثابتًا إلى الفصل، كما يلي:

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

الآن أريد توسيع هذا الفصل للسماح بكمية عشوائية من نقاط التحكم.لذلك أريد تغيير هذا إلى:

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

والسؤال هو ما إذا كان من الأفضل تخزين الثوابت في أساليب للبدء بها، لتسهيل القدرة على التكيف.بمعنى آخر، أليس من الأفضل أن نبدأ بهذه الطريقة:

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

وميزة ذلك هي أنه كان بإمكاني تغيير رمز واحد فقط في الطريقة المعنية، بدلاً من التحرك حول الثوابت وما إلى ذلك.

هل هذه ممارسة جيدة أم سيئة؟

هل كانت مفيدة؟

المحلول

وعادة أنا يفضلون الحفاظ على أقل عدد ممكن صلات يدويا وقت ممكن.

وعدد من نقاط المراقبة في منحنى هو، أيضا، على عدد من نقاط المراقبة في المنحنى. انها ليست المتغير المستقل التي يمكن تعيينها في الإرادة.

وهكذا وعادة ما سيعرض على CONST إشارة حاوية قياسية:

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

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

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

وإذا كنت تريد أن تعرف كم عدد نقاط المراقبة، ثم استخدم curve.getControlPoints().size(). كنت أظن أنه في معظم حالات الاستخدام كنت تريد النقاط فضلا عن عدد على أي حال، وتعريض حاوية قياسية يمكنك استخدام التعابير مكرر والخوارزميات المدمج في المكتبة القياسية، وليس الحصول على العد والدعوة وظيفة مثل getControlPointWithIndex في حلقة.

وإذا كان هناك حقا أي شيء آخر في الدرجة منحنى، وأنا قد تذهب إلى أبعد مثل:

typedef std::vector<Point> Curve;

و(غالبا ما منحنى لا تجعل نفسها، كطبقة العارض يمكن أن يكون من التفاصيل حول خط أنبوبي، وترك منحنى كما محض قطعة أثرية هندسية)

نصائح أخرى

int getControlPointCount() {return _controlPointCount;}

هذا هو الوصول.لا يعد تبديل ثابت ثابت للموصل مكسبًا حقًا كما أشار litb.ما تحتاجه حقًا برهان المستقبل من المحتمل أن يكون زوجًا من الملحقات والمتحولات.

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

أود أيضًا أن أضع تصميمًا للملحق وأقوم بعمله:

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

وما يقابلها:

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

الآن، الاختلاف الكبير مع الكائن الثابت هو أن عدد نقاط التحكم لم يعد سمة على مستوى الفئة بل على مستوى المثيل الأول.هذا ال تغيير التصميم.هل تريدها بهذه الطريقة؟

أحمق: عدد ثابت على مستوى الفصل الخاص بك هو public وبالتالي لا يحتاج إلى ملحق.

لإجابة على سؤالك بشكل أفضل، ينبغي للمرء أن نعرف أيضا كيف يتم تعيين متغير controlPointCount. والتي وضعتها خارج من صفك؟ في هذه الحالة، يجب عليك أيضا تحديد اضع. أو الطبقة المنحنى هو الوحيد المسؤول عن تحديد ذلك؟ هو فقط تعيين في وقت الترجمة أو أيضا على وقت التشغيل.

وعلى أي حال، تجنب الرقم السحري حتى في هذا النموذج:

int getControlPointCount() {return 8;}

وهذا هو أفضل:

int getControlPointCount() {return CONTROL_POINT_COUNT;}

وهناك طريقة لديه ميزة أنه يمكنك تعديل تطبيق داخلي (استخدام قيمة ثابتة، وقراءة من ملف التكوين، تغيير قيمة حيوي)، دون أن يؤثر ذلك خارجية للفئة.

class Curve
{   
    private:
        int _controlPointCount;

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

    public:      
        curve()
        {
            _controlPointCount = 8;
        }

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

وسوف أقوم بإنشاء مدونة من هذا القبيل، مع وظيفة مجموعة في القطاع الخاص، بحيث لا يستطيع الجسم تلعب مع العد نقطة مراقبة، حتى ننتقل إلى المرحلة التالية من development..where نقوم بتحديث بداية لتحديث عدد نقاط المراقبة في وقت التشغيل. في ذلك الوقت، ونحن يمكن ان تتحرك هذه الطريقة مجموعة من القطاع الخاص إلى النطاق العام.

أثناء فهم السؤال، لدي عدد من المشاكل المفاهيمية مع المثال:

  • ما هي قيمة الإرجاع ل getControlPointCount() عندما لا يكون عدد نقاط المراقبة محدودا؟
    • هل هو ماكسينت؟
    • هل هو العدد الحالي لنقاط التحكم على المنحنى (وبالتالي كسر المنطق الذي يقول أن هذا هو أكبر عدد ممكن من النقاط؟)
  • ماذا يحدث عندما تحاول بالفعل إنشاء منحنى بنقاط MAXINT؟سوف تنفد الذاكرة في نهاية المطاف.

الواجهة نفسها تبدو مشكلة بالنسبة لي.مثل فئات المجموعة القياسية الأخرى، يجب أن يكون الفصل قد قام بتغليف حدوده على عدد النقاط، وحدوده AddControlPoint() يجب أن يُرجع خطأ في حالة حدوث قيود على الحجم أو الذاكرة أو أي انتهاك آخر.

أما بالنسبة للإجابة المحددة، فأنا أتفق مع كيجاناكاكيس:تتيح وظيفة العضو مزيدًا من المرونة.

وأنا أميل إلى استخدام التكوين المستمر + (القيمة الافتراضية) لجميع القيم "مستقرة" من خلال تنفيذ البرنامج. مع ثوابت واضحة للقيم التي لا يمكن تغيير (360 درجة - راديان> 2 بي، 60 ثانية -> 1 دقيقة) أو التي تغير من شأنه كسر شفرة تشغيل (الحد الأدنى / الحد الأقصى قيم الخوارزميات التي تجعلها غير مستقرة)

.

وأنت تتعامل مع بعض القضايا التصميم المختلفة. أولا يجب أن تعرف ما إذا كان عدد من نقاط المراقبة هو قيمة مستوى فئة أو مثيل. ثم ما اذا كان هو ثابت في أي من مستويين.

وإذا كان كل منحنيات يجب أن تشترك في نفس عدد نقاط المراقبة في التطبيق الخاص بك ثم هو مستوى الطبقة قيمة (ثابتة). إذا منحنيات مختلفة يمكن أن يكون عدد مختلف من نقاط المراقبة فلا قيمة مستوى الدرجة، وإنما على مستوى حالة واحدة.

في هذه الحالة، إذا كان عدد من نقاط المراقبة سوف يكون ثابتا خلال حياة كاملة من المنحنى ثم هو مستوى سبيل المثال مستمر، إذا كان يمكن تغيير ثم فإنه ليس ثابتا عند هذا المستوى سواء.

// 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() );
}

لنوع لا يتجزأ أنا غن باستخدام:

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

إذا لا ثابت الحاجة إلى أي كيانات باستثناء تطبيق فئة أعلن الثوابت في ملف * .CPP.

namespace
{
const int CONTROL_POINT_COUNT = 8;
}

في عام، يجب أن تكون جميع البيانات الخاصة بك الخاص والوصول إليها عبر حاصل على واضعي. وإلا فإنك تنتهك التغليف. وهي، إذا كنت تعرض البيانات الأساسية التي قفل نفسك وصفك إلى تمثيل معين من أن البيانات الأساسية.

في هذه الحالة المحددة لكنت قد فعلت شيئا كما يلي أعتقد:

class Curve
{

   protected:

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

   private:

      static int _controlPointCount = 0;
};

لا يجب أن يتم تعريف الثوابت بشكل عام داخل الأساليب. على سبيل المثال كنت اختيار اثنين من ميزات فريدة من نوعها. أولا، انها جالبة. الثانية، ونوع إعادتهم هو عدد صحيح. ولكن النقطة من الثوابت التي تحدد هي لاستخدامها أكثر من مرة واحدة، وتكون قادرة على الرجوع إليها بطريقة مريحة. كتابة "8" بدلا من "controlPointCount" قد يوفر لك الوقت، وربما لا يبدو أن تتكبد تكاليف الصيانة، ولكن هذا لن يكون عادة صحيحا إذا كنت دائما تعريف الثوابت داخل الأساليب.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top