يجب كتابة طريقة واحدة لتحويل مسافات أو مجموعة من الأساليب ؟

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

  •  05-07-2019
  •  | 
  •  

سؤال

أنا مجرد تعلم C++ والبرمجة.أنا خلق فئة تسمى Distance.أريد أن تسمح للمستخدم (مبرمج باستخدام), صفي القدرة على تحويل مسافات من وحدة قياس إلى أخرى.على سبيل المثال:بوصة -> سم, ميل -> كيلومترا ، الخ...

مشكلتي هي أنني أريد أن يكون أسلوب واحد يسمى ConvertTo التي من شأنها تحويل أي وحدة قياس.

هذا ما لدي حتى الآن:

// unit_of_measure is an enum containg all my supported lengths,
// (eg. inches, centimeters, etc...)
int Distance::ConvertTo(unit_of_measure convert_unit)
{
    switch (convert_unit)
    {
        case inches:
            if (unit != inches) {
                if (unit == centimeters) {
                    distance *= CM_TO_IN;
                    unit = inches;
                    return 0;
                } else {
                    cerr << "Conversion not possible (yet)." << endl;
                    return 1;
                }
            } else {
                cout << "Warning: Trying to convert inches to inches." << endl;
                return 2;
            }
        case centimeters:
            if (unit != centimeters) {
                if (unit == inches) {
                    distance /= CM_TO_IN;
                    unit = centimeters;
                    return 0;
                } else {
                    cerr << "Conversion not possible (yet)." << endl;
                    return 1;
                }
            } else {
                cout << "Warning: Trying to convert inches to inches." << endl;
                return 2;
            }
// I haven't written anything past here yet because it seems
// like a bad idea to keep going with this huge switch 
// statement.
        default:
            cerr << "Undefined conversion unit." << endl;
            return -1;
    }
}

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

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

المحلول

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

double inchesToCentimeters(double inches);
double centimetersToInches(double cent);

وظيفة أسماء اقول لكم بالضبط ما وظيفة الاتصال و لا يوجد تحتاج إلى تمرير في الزائد المعلمة أن يتتبع الوحدات.

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

عند استخدام وحدة مشتركة ، فإنك توفر على نفسك الكثير من وظيفة الكتابة.أقول المشترك المسافة وحدة مربع ، الآن مرة كتابة وظائف تحويل من متر إلى كل وحدة تحتاج من جميع وحدات أخرى إلى مربع, يمكنك الجمع بين هذه إلى الذهاب من أي وحدة إلى متر - إلى أي وحدة أخرى.

نصائح أخرى

توجهي سيكون دائما تخزين المسافة في نفس الوحدة.هذا يتجنب دائما الحاجة إلى التحقق الوحدات الخاصة بك عندما كنت في حاجة لتحويل القيمة.

الهيكل العظمي من قانون قد تبدو شيئا مثل هذا:

class Distance
{
public:

   float ConvertTo (unit_of_measure convert_unit)
   {
      return (_distanceInInches * getConversionFactor(convert_unit));
   }

   float SetValue (unit_of_measure unit, float value)
   {
      _distanceInInches = (value / getConversionFactor(unit));
   }

private:   

   float getConversionFactor(unit_of_measure unit)
   {
      switch(unit)
      {
         // add each conversion factor here
      }
   }

   float _distanceInInches;
}

إذا كنت لا تمانع في الاعتماد على استخدام دفعة.الوحدات

إذا كنت تريد أن تبقي بالضبط الحالي API, ولكن تبسيط تنفيذها ، لماذا لا تمثل الوحدة من حيث بعض التعسفي القياسية (على سبيل المثال1 متر).على الأقل بدلا من الاضطرار ن^2 (المصدر->دست) الاحتمالات ، 2*N (المصدر->std) (std->دست) التحويلات.

struct distance_unit {
   char const* name;
   double meters_per_unit;
   distance_unit() : name("meters"),meters_per_unit(1.) {}
   double to_meters(double in_units) { return in_units/meters_per_unit; }
   double to_units(double in_meters) { return in_meters*meters_per_unit; }
};

struct distance {
   double d;
   distance_unit unit;
   distance(double d,distance_unit const& unit) : d(d),unit(unit) {}
   distance(double meters,distance_unit const& unit,bool _)
      : d(unit.to_units(meters)),unit(unit) {}
   distance convert_to(distance_unit const& to) {
        return distance(unit.to_meters(d),to,false);
   }
   friend inline std::ostream& operator<<(std::ostream &o) {
      return o << d << ' ' << unit.name;
   }
};

بالطبع الفائدة الوحيدة لهذا هو أن بالضبط قابل للتمثيل المسافات (في الوحدة) لن تصبح غير دقيق.إذا كنت لا تهتم حول التقريب الدقيق المساواة من مبالغ هذا هو أكثر عقلانية:

struct distance {
   double meters;
   distance_unit preferred_unit;
   distance(double d,distance_unit const& unit) 
     : meters(unit.to_meters(d)),preferred_unit(unit) {}
   distance(double meters,distance_unit const& unit,bool _)
     : meters(meters),preferred_unit(unit)
   distance convert_to(distance_unit const& to) { 
       return distance(meters,to,false);
   }
   friend inline std::ostream& operator<<(std::ostream &o) {
      return o << unit.to_units(meters) << ' ' << unit.name;
   }

};

إذا كنت تستخدم الخاصة بلبنان ، إنشاء خريطة خريطة التحويل المستمر.حتى تتمكن من الحصول على التحويل المستمر من "من" و "إلى".

شيء من هذا القبيل:

std::map <unit_of_measure, std::map<unit_of_measure, double>> ConversionConstants_FromTo;

ConversionConstants_FromTo(inches)(centimeters) = ...;
ConversionConstants_FromTo(inches)(miles)       = ...;

int Distance::ConvertTo(unit_of_measure convert_unit) {
    return distance*ConversionConstants_FromTo(unit, convert_unit)
}

هناك مستويين من التحليل أود أن السلوك.

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

الآن أنا لا أحب مثل هذه جليل واجهة.لماذا لا واجهة مثل

 Distance {

      Distance(unit, value) { // constructor

      float getValue(unit) throws UnsupportedUnitException;
 }

لذلك ليس هناك حاجة المتصل لديك أي فكرة الوحدات الداخلية من المسافة.لا جليل السلوك.

ثم بيان التبديل هو واضح المتكررة.يجب أن يكون المرشح لبعض إعادة بيع ديون.

كل التحويل يمكن التعبير عن الضرب.هل يمكن أن يكون الجدول ، وحفظ جميع عوامل التحويل لك الدعم.بحيث يكون لديك

       float getConversionFactor(fromUnit, toUnit) throws UnsupportedUnitException

والتي لا البحث من معامل التحويل ، ومن ثم تطبيقه في getValue() طريقة

       getValue(requestedUnit) {
             return value * getConversionfactor(myUnit, requestedUnit);
       }

في حين كنت لا تزال التعلم ، قد يكون من المفيد التخلي عن استخدام التبديل التعداد نهج لصالح عائلة من البنيات واحد في التعامل مع الوحدة ، كل منها يحتوي على قيمة المدخلات و علامة فريدة النوع لجعلها مختلفة.وهذا له بعض المزايا:

  1. التحويلات يمكن أن يتم عن طريق الزائدة من وظيفة مع الاسم الشائع ("تحويل" ربما؟) مما يجعل الحياة أسهل إذا كنت تريد أن تفعل التحويلات في قالب المدونة.
  2. نوع النظام يعني أنك لم بطريق الخطأ تحويل غالون إلى سنة ضوئية كما أنك لن تكتب الزائد المترجم أن مباراة الأبعاد غير مناسب التحويلات.
  3. وقت التنفيذ من التبديل أو متداخلة إذا كتل يعتمد على عدد من الشروط الزائد النهج تحولت في وقت الترجمة

الجانب السلبي سيكون النفقات العامة من إنشاء تلك العائلة من الوسم والطبقات وضرورة التفاف حججك في فئة (البنية الأرجح) المناسبة.مرة واحدة ملفوفة لن المعتاد الرقمية مشغلي إلا كتب لهم.

تقنية تستحق التعلم على الرغم من المنظمة البحرية الدولية.

وهنا اثنين من أكثر الأشياء للتفكير لأن هناك بالفعل عدد غير قليل من الأفكار الجيدة جدا تطوف هنا.

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

namespace Convert {
  double inchesToCentimeters(double inches) { ... }
  double inchesToMeters(double inches) { ... }
} // end Convert namespace

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

class Convert {
public:
  static Convert fromInches(double inches) {
      return Convert(inches * 0.0254);
  }
  static Convert fromCentimeters(double cm) {
      return Convert(cm / 100.0);
  }
  ...
  double toInches() const { return meters * 39.370079; }
  double toCentimeters() const { return meters * 100.0; }
  ...
protected:
  Convert(double meters_): meters(meters_) {}
private:
  double meters;
};

وهذا سيجعل المستخدم الخاص بك-قانون الأراضي جدا للقراءة يمكنك جني الفوائد من اختيار ما الداخلي وحدة يجعل حياتك سهلة جدا.

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

بدلا من بيان التبديل ، يمكنك استخدام الجدول من عوامل القياس مثلا ، بين المحددة وحدة وحدة.

أيضا إلقاء نظرة على دفعة.الوحدات, ليس هو حل المشكلة ، لكنها قريبة بما يكفي لتكون مثيرة للاهتمام.

أود أن الجمع بين NawaMan و ph0enix الجواب.بدلا من وجود خريطة من خرائط فقط 2 خرائط كاملة من الثوابت.خريطة واحدة يحتوي على التحويل من متر, خريطة أخرى تحتوي معكوس.ثم وظيفة هو شيء من هذا القبيل (في شبة الكود):

function convertTo (baseUnitName, destinationUnitName) {
    let A = getInverseConstant(baseUnitName);
    let B = getConstant(destinationUnitName);

    return this.baseUnit*A*B;
}

الذي هو أقصر بكثير من الخاص بك الجبلية التبديل التبديل بيان اثنين من خرائط كاملة من الثوابت هي أسهل بكثير للحفاظ على من بيان التبديل ، على ما أعتقد.خريطة من خرائط الأساس يكون مجرد طاولة مرات فقط من متجر الرأسي والأفقي cooeficients بدلا من n*m كتلة من الذاكرة.

يمكنك حتى كتابة التعليمات البرمجية لقراءة الثوابت من ملف نصي ومن ثم توليد معكوس الثوابت مع 1/x على كل قيمة.

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