سؤال

على غرار هو الثابت-ترميز حرفية من أي وقت مضى مقبول ؟ , ولكن أنا على وجه التحديد التفكير من "السحر السلاسل" هنا.

على مشروع كبير علينا مائدة من خيارات التكوين مثل هذه:

Name         Value
----         -----
FOO_ENABLED  Y
BAR_ENABLED  N
...

(مئات منهم).

الممارسة الشائعة هو استدعاء دالة عامة لاختبار خيارا مثل هذا:

if (config_options.value('FOO_ENABLED') == 'Y') ...

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

عند إضافة خيار جديد, كنت تفكر في إضافة وظيفة لإخفاء "السلسلة السحرية" مثل هذا:

if (config_options.foo_enabled()) ...

ولكن الزملاء فكرت تمادى و اعترض على القيام بذلك ، مفضلا الثابت-ترميز لأن:

  • هذا ما نقوم به عادة
  • فإنه يجعل من السهل أن نرى ما يحدث عند تصحيح الكود

المشكلة هي أن أرى وجهة نظرهم!واقعيا, نحن لن تسمية الخيارات لأي سبب من الأسباب ، وذلك عن الميزة الوحيدة أستطيع أن أفكر في بلدي وظيفة هو أن المترجم سوف التقاط أي مطبعي مثل fo_enabled () ، ولكن ليس 'FO_ENABLED'.

ماذا تعتقد ؟ هل فاتني أي مزايا/عيوب ؟

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

المحلول

if (config_options.isTrue('FOO_ENABLED')) {...
}

تقييد الثابت ترميز Y تحقق إلى مكان واحد ، حتى لو كان ذلك يعني كتابة المجمع الدرجة على الخريطة الخاصة بك.

if (config_options.isFooEnabled()) {...
}

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

if (config_options.isTrue(ConfigKeys.FOO_ENABLED)) {...
}

نصائح أخرى

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

إذا كنت تستخدم سلسلة مرتين في الكود, سوف النظر في مما يجعلها ثابتة.

إذا كنت تستخدم سلسلة ثلاث مرات في المدونة سوف يكاد يكون من المؤكد جعله المستمر.

أدرك أن السؤال قديم ، لكنه جاء على الهامش.

AFAIC ، القضية هنا لم يتم تحديدها بدقة ، سواء في السؤال أو الإجابات.ننسى 'harcoding السلاسل" أو لا للحظة.

  1. قاعدة البيانات تحتوي على الجدول المرجعي ، تحتوي config_options.PK هو سلسلة.

  2. هناك نوعان من PKs:

    • معنى معرفات أن المستخدمين (و المطورين) ؟ هذه PKs المفترض أن تكون مستقرة ويمكن الاعتماد عليها.

    • لا معنى لها Id الأعمدة التي يجب على المستخدمين لا نرى أن المطورين يجب أن تكون على علم ، رمز حولها.هذه لا يمكن الاعتماد عليها.

  3. فمن العادي, العادية, إلى كتابة التعليمات البرمجية باستخدام قيمة مطلقة ذات مغزى PK IF CustomerCode = "IBM" ... أو IF CountryCode = "AUS" الخ.

    • الرجوع إلى قيمة مطلقة لا معنى لها PK غير مقبول (بسبب زيادة تلقائية;الثغرات التي يجري تغييرها ؛ القيم محل الجملة).
      .
  4. المرجع الخاص بك يستخدم الجدول معنى PKs.الرجوع إلى تلك الحرفي السلاسل في قانون لا مفر منه.إخفاء قيمة سيجعل صيانة أكثر صعوبة ؛ قانون لم يعد حرفيا ؛ الزملاء صحيح.بالإضافة إلى أن هناك الإضافية الزائدة الدالة على أن يمضغ دورات.إذا كان هناك خطأ مطبعي في حرفية, سوف تجد قريبا أن من خلال ديف الاختبار قبل وقت طويل ضد التعذيب.

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

    • المهم هو محاولة إخفاء الحرفي لا قيمة له.
      .

  5. فإنه لا يمكن أن يفسر على أنه "hardcoding" ، وهذا هو شيء مختلف تماما.أعتقد أن هذا هو المكان المشكلة هو تحديد هذه التركيبات باسم "ضمنية".هو مجرد الرجوع Meaningfull PK حرفيا.

  6. الآن من وجهة نظر أي مقطع التعليمات البرمجية فقط ، إذا كنت تستخدم نفس القيمة عدة مرات ، يمكنك تحسين التعليمات البرمجية عن طريق التقاط سلسلة حرفية في متغير ومن ثم استخدام متغير في بقية كتلة التعليمات البرمجية.بالتأكيد ليست وظيفة.ولكن هذا هو الكفاءة والممارسة الجيدة المسألة.حتى هذا لا يغير من تأثير IF CountryCode = @cc_aus

في تجربتي, هذا النوع من القضايا هو اخفاء مشكلة أعمق:عدم القيام الفعلي OOP و اتباع مبدأ الجافة.

باختصار, التقاط القرار في وقت بدء التشغيل من خلال التعريف المناسب لكل عمل داخل على if البيانات ، ومن ثم رمي بعيدا كل config_options و وقت تشغيل الاختبارات.

التفاصيل أدناه.

العينة تم استخدام:

if (config_options.value('FOO_ENABLED') == 'Y') ...

الأمر الذي يثير السؤال واضح: "ما يجري في الحذف?", لا سيما في ضوء البيان التالي:

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

دعونا نفترض أن كل من هذه config_option القيم حقا لا تتوافق مع مشكلة واحدة المجال (أو تنفيذ استراتيجية) مفهوم.

بدلا من القيام بذلك (مرارا وتكرارا في أماكن مختلفة في جميع أنحاء رمز):

  1. اتخاذ سلسلة (الوسم),
  2. تجد في المقابل سلسلة أخرى (قيمة) ،
  3. اختبار قيمة منطقية-ما يعادلها ،
  4. على أساس هذا الاختبار ، أن يقرر ما إذا كان تنفيذ بعض الإجراءات.

أقترح تغليف مفهوم "شكلي العمل".

لنأخذ كمثال على ذلك (من الواضح تماما كما hypthetical كما FOO_ENABLED ...;-) التعليمات البرمجية يجب أن تعمل إما باللغة الإنجليزية أو وحدات أو وحدات متري.إذا METRIC_ENABLED هو "صحيح" ، تحويل البيانات التي أدخلها المستخدم من المقياس إلى اللغة الإنجليزية الداخلية حسابية وتحويل الظهر قبل عرض النتائج.

تعريف واجهة:

public interface MetricConverter {
    double toInches(double length);
    double toCentimeters(double length);
    double toPounds(double weight);
    double toKilograms(double weight);
}

الذي يحدد في مكان واحد كل سلوك يرتبط مع مفهوم METRIC_ENABLED.

ثم كتابة تطبيقات ملموسة من جميع طرق هذه السلوكيات هي التي يتعين الاضطلاع بها:

public class NullConv implements MetricConverter {
    double toInches(double length) {return length;}
    double toCentimeters(double length) {return length;}
    double toPounds(double weight)  {return weight;}
    double toKilograms(double weight)  {return weight;}
}

و

// lame implementation, just for illustration!!!!
public class MetricConv implements MetricConverter {
    public static final double LBS_PER_KG = 2.2D;
    public static final double CM_PER_IN = 2.54D
    double toInches(double length) {return length * CM_PER_IN;}
    double toCentimeters(double length) {return length / CM_PER_IN;}
    double toPounds(double weight)  {return weight * LBS_PER_KG;}
    double toKilograms(double weight)  {return weight / LBS_PER_KG;}
}

في وقت بدء التشغيل بدلا من تحميل مجموعة من config_options القيم تهيئة مجموعة من شكلي الإجراءات, كما في:

MetricConverter converter = (metricOption()) ? new MetricConv() : new NullConv();

(حيث التعبير metricOption() أعلاه هو الوقوف في كل ما مرة واحدة فقط تحقق تحتاج إلى جعل ، بما في ذلك النظر في قيمة METRIC_ENABLED ;-)

ثم أينما رمز قد قال:

double length = getLengthFromGui();
if (config_options.value('METRIC_ENABLED') == 'Y') {
    length = length / 2.54D;
}
// do some computation to produce result
// ...
if (config_options.value('METRIC_ENABLED') == 'Y') {
    result = result * 2.54D;
}
displayResultingLengthOnGui(result);

إعادة كتابتها كما يلي:

double length = converter.toInches(getLengthFromGui());
// do some computation to produce result
// ...
displayResultingLengthOnGui(converter.toCentimeters(result));

لأن كل تفاصيل التنفيذ ذات الصلة إلى أن مفهوم واحد الآن تعبئتها نظيفة, جميع الصيانة المستقبلية ذات الصلة METRIC_ENABLED يمكن أن يتم في مكان واحد.وبالإضافة إلى ذلك ، فإن وقت التشغيل المفاضلة هو الفوز ؛ إن "علوية" الاحتجاج طريقة تافهة بالمقارنة مع النفقات العامة من جلب قيمة سلسلة من خريطة وأداء سلسلة#يساوي.

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

علاوة على ذلك يمكنك الحصول على كتابتها وظائف, الآن يبدو لك فقط تخزين القيم المنطقية ، ما إذا كنت بحاجة لتخزين int, string.... الخوأود أن بدلا من استخدام get_foo() مع نوع من get_string("FOO") أو get_int("FOO").

أنا حقا يجب استخدام الثوابت لا الثابت ترميز حرفية.

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

أعتقد أن هناك اثنين من مختلف القضايا هنا:

  • في المشروع الحالي اتفاقية استخدام ترميز-الثابت سلاسل راسخة ، حتى يتسنى لجميع المطورين الذين يعملون على المشروع على دراية به.قد يكون دون المستوى الأمثل الاتفاقية لجميع الأسباب التي تم سردها, لكن الجميع على دراية رمز يمكن أن ننظر في الأمر و يعرف غريزيا ما يفترض القيام به.تغيير التعليمات البرمجية بحيث في أجزاء معينة ، ويستخدم "جديدة" وظيفة سيجعل رمز قليلا من الصعب قراءة (لأن الناس سوف تضطر إلى التفكير وتذكر ماذا الاتفاقية الجديدة لا) وبالتالي أصعب قليلا للحفاظ على.ولكن أعتقد أن تغيير على المشروع بأكمله إلى اتفاقية جديدة يحتمل أن تكون باهظة التكاليف إلا إذا كنت يمكن بسرعة النصي التحويل.
  • على جديد مشروع رمزية الثوابت هي الطريقة المنظمة البحرية الدولية لجميع الأسباب المذكورة. خاصة لأن أي شيء يجعل المترجم التقاط الأخطاء في وقت الترجمة وإلا سوف يتم القبض عليك من قبل الإنسان في وقت التشغيل هو مفيد جدا الاتفاقية إلى إنشاء.

أنا أيضا يفضلون كتابة بشدة فئة التكوين إذا تم استخدامه من خلال الرمز.مع الاسم بشكل صحيح أساليب لا تفقد أي القراءة.إذا كنت بحاجة إلى القيام التحويلات من السلاسل إلى نوع بيانات آخر (عشري/العوامة/الباحث), أنت لا تحتاج إلى تكرار التعليمات البرمجية التي يقوم التحويل في أماكن متعددة و يمكن أن ذاكرة التخزين المؤقت نتيجة لذلك التحويل يقام مرة واحدة.كنت قد حصلت بالفعل على أساس هذا في مكان بالفعل لذلك أنا لا أعتقد أنها سوف تأخذ الكثير من التعود على جديد طريقة عمل الأشياء.

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

const string HELLO_WORLD = "Hello world!";
print(HELLO_WORLD);

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

print("Hello world!");

هنا نحن لسنا على يقين من ذلك.هل مبرمج حقا لا تريد هذه السلسلة أن تكون مترجمة أو لم مبرمج ننسى التعريب بينما كان كتابة هذا الرمز ؟

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