ما هي أفضل طريقة لتنفيذ الثوابت في جافا؟[مغلق]

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

  •  09-06-2019
  •  | 
  •  

سؤال

لقد رأيت أمثلة مثل هذا:

public class MaxSeconds {
   public static final int MAX_SECONDS = 25;
}

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

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

المحلول

وهذا أمر مقبول تماما، وربما حتى المعيار.

(public/private) static final TYPE NAME = VALUE;

أين TYPE هو النوع، NAME هو الاسم بالأحرف الكبيرة مع الشرطة السفلية للمسافات، و VALUE هي القيمة الثابتة.

أوصي بشدة بعدم وضع ثوابتك في فئاتها أو واجهاتها الخاصة.

كملاحظة جانبية:لا يزال من الممكن تغيير المتغيرات التي تم الإعلان عنها نهائية وقابلة للتغيير؛ومع ذلك، لا يمكن للمتغير أن يشير أبدًا إلى كائن مختلف.

على سبيل المثال:

public static final Point ORIGIN = new Point(0,0);

public static void main(String[] args){

    ORIGIN.x = 3;

}

وهذا قانوني و ORIGIN ستكون عندها نقطة عند (3، 0).

نصائح أخرى

أنصح بشدة بعدم وجود فئة ثوابت واحدة.قد تبدو فكرة جيدة في ذلك الوقت، ولكن عندما يرفض المطورون توثيق الثوابت وينمو الفصل ليشمل ما يزيد عن 500 ثابت لا ترتبط جميعها ببعضها البعض على الإطلاق (كونها مرتبطة بجوانب مختلفة تمامًا من التطبيق)، فإن هذا يتحول عمومًا إلى ملف الثوابت غير قابل للقراءة تمامًا.بدلاً من:

  • إذا كان لديك حق الوصول إلى Java 5+، فاستخدم التعدادات لتحديد ثوابتك المحددة لمنطقة التطبيق.يجب أن تشير جميع أجزاء منطقة التطبيق إلى التعدادات، وليس إلى القيم الثابتة، لهذه الثوابت.يمكنك الإعلان عن تعداد مشابه لكيفية إعلانك عن الفصل الدراسي.ربما تكون التعدادات هي الميزة الأكثر (وربما الوحيدة) المفيدة في Java 5+.
  • إذا كانت لديك ثوابت صالحة فقط لفئة معينة أو إحدى فئاتها الفرعية، فقم بإعلانها إما محمية أو عامة وضعها في الفئة العليا في التسلسل الهرمي.بهذه الطريقة، يمكن للفئات الفرعية الوصول إلى هذه القيم الثابتة (وإذا وصلت الفئات الأخرى إليها عبر الجمهور، فإن الثوابت ليست صالحة لفئة معينة فقط... مما يعني أن الفئات الخارجية التي تستخدم هذا الثابت قد تكون مقترنة بإحكام شديد بـ فئة تحتوي على الثابت)
  • إذا كانت لديك واجهة ذات سلوك محدد، ولكن القيم التي تم إرجاعها أو قيم الوسيطات يجب أن تكون محددة، فمن المقبول تمامًا تحديد الثوابت على تلك الواجهة حتى يتمكن المنفذون الآخرون من الوصول إليها.ومع ذلك، تجنب إنشاء واجهة للاحتفاظ بالثوابت فقط:يمكن أن يصبح سيئًا مثل الفصل الذي تم إنشاؤه فقط للاحتفاظ بالثوابت.

إنها سوء الممارسة لاستخدام الواجهات فقط للاحتفاظ بالثوابت (المسماة نمط واجهة ثابت بواسطة جوش بلوخ).إليك ما ينصح به جوش:

إذا كانت الثوابت مرتبطة بقوة بفئة أو واجهة موجودة ، فيجب عليك إضافتها إلى الفصل أو الواجهة.على سبيل المثال ، جميع الطبقات البدائية العددية المعبأة ، مثل عدد صحيح ومزدوج ، تصدير MIN_VALUE و MAX_VALUE.إذا كان من الأفضل النظر إلى الثوابت كأعضاء من نوع مُعود ، فيجب عليك تصديرها بـ التعداديكتب.خلاف ذلك ، يجب عليك تصدير الثوابت بفئة فائدة غير ثابتة.

مثال:

// Constant utility class
package com.effectivejava.science;
public class PhysicalConstants {
    private PhysicalConstants() { }  // Prevents instantiation

    public static final double AVOGADROS_NUMBER   = 6.02214199e23;
    public static final double BOLTZMANN_CONSTANT = 1.3806503e-23;
    public static final double ELECTRON_MASS      = 9.10938188e-31;
}

حول اصطلاح التسمية:

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

في Java الفعالة (الإصدار الثاني)، يوصى باستخدام التعدادات بدلاً من ints الثابتة للثوابت.

توجد كتابة جيدة عن التعدادات في Java هنا:http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html

لاحظ أن السؤال المطروح في نهاية هذا المقال هو:

إذن متى يجب عليك استخدام التعدادات؟

مع إجابة:

في أي وقت تحتاج إلى مجموعة ثابتة من الثوابت

فقط تجنب استخدام الواجهة:

public interface MyConstants {
    String CONSTANT_ONE = "foo";
}

public class NeddsConstant implements MyConstants {

}

إنه أمر مغري، لكنه ينتهك التغليف ويطمس التمييز بين تعريفات الفئة.

أستخدم النهج التالي:

public final class Constants {
  public final class File {
    public static final int MIN_ROWS = 1;
    public static final int MAX_ROWS = 1000;

    private File() {}
  }

  public final class DB {
    public static final String name = "oups";

    public final class Connection {
      public static final String URL = "jdbc:tra-ta-ta";
      public static final String USER = "testUser";
      public static final String PASSWORD = "testPassword";

      private Connection() {}
    }

    private DB() {}
  }

  private Constants() {}
}

من، على سبيل المثال، أستخدم Constants.DB.Connection.URL للحصول على ثابت.يبدو أكثر "توجيهاً نحو الكائن" بالنسبة لي.

قد يؤدي إنشاء ثوابت نهائية ثابتة في فصل دراسي منفصل إلى وقوعك في مشكلة.سيقوم مترجم Java بتحسين ذلك فعليًا ووضع القيمة الفعلية للثابت في أي فئة تشير إليه.

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

بدلًا من التفكير فيها كثوابت، فكر فيها كمعلمات تكوين وقم بإنشاء فئة لإدارتها.اجعل القيم غير نهائية، وفكر أيضًا في استخدام الحروف.في المستقبل، عندما تحدد أن بعض هذه المعلمات يجب أن تكون قابلة للتكوين من قبل المستخدم أو المسؤول، سيكون من الأسهل القيام بذلك.

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

بدلاً من ذلك، يجب أن تنتقل الثوابت إلى الفئة التي "تمتلكها".هل لديك ثابت يسمى TIMEOUT؟من المحتمل أن ينتقل إلى فئة Communications() أو Connection() الخاصة بك.MAX_BAD_LOGINS_PER_HOUR؟يذهب إلى المستخدم ().وهلم جرا وهكذا دواليك.

الاستخدام الآخر المحتمل هو ملفات Java.properties عندما يمكن تعريف "الثوابت" في وقت التشغيل، ولكن ليس من السهل تغييرها بواسطة المستخدم.يمكنك تجميعها في .jars الخاصة بك والرجوع إليها باستخدام Class ResourceLoader.

هذا هو الطريق الصحيح للذهاب.

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

ماذا عن التعداد؟

أفضّل استخدام الحروف بدلاً من الثوابت.قد تُرجع هذه الحروف قيمًا ثابتة، على سبيل المثال. public int getMaxConnections() {return 10;}, ، ولكن أي شيء يحتاج إلى الثابت سوف يمر عبر أداة getter.

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

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

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

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

ال public|private static final TYPE NAME = VALUE; النمط هو وسيلة جيدة للإعلان عن ثابت.شخصيًا، أعتقد أنه من الأفضل تجنب إنشاء فصل دراسي منفصل يضم جميع ثوابتك، لكنني لم أر أبدًا سببًا لعدم القيام بذلك، بخلاف التفضيل الشخصي والأسلوب.

إذا كان من الممكن تصميم ثوابتك بشكل جيد كتعداد، ففكر في التعداد الهيكل متاح في 1.5 أو الأحدث.

إذا كنت تستخدم إصدارًا أقدم من 1.5، فلا يزال بإمكانك تنفيذ التعدادات الآمنة باستخدام فئات Java العادية.(يرى هذا الموقع للمزيد عن ذلك).

بناءً على التعليقات أعلاه، أعتقد أن هذا أسلوب جيد لتغيير الفئة الثابتة العالمية القديمة (التي تحتوي على متغيرات نهائية ثابتة عامة) إلى ما يعادلها من التعداد بطريقة مثل هذه:

public class Constants {

    private Constants() {
        throw new AssertionError();
    }

    public interface ConstantType {}

    public enum StringConstant implements ConstantType {
        DB_HOST("localhost");
        // other String constants come here

        private String value;
        private StringConstant(String value) {
            this.value = value;
        }
        public String value() {
            return value;
        }
    }

    public enum IntConstant implements ConstantType {
        DB_PORT(3128), 
        MAX_PAGE_SIZE(100);
        // other int constants come here

        private int value;
        private IntConstant(int value) {
            this.value = value;
        }
        public int value() {
            return value;
        }
    }

    public enum SimpleConstant implements ConstantType {
        STATE_INIT,
        STATE_START,
        STATE_END;
    }

}

إذن يمكنني أن أحيلهم إلى مثل:

Constants.StringConstant.DB_HOST

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

هناك قدر معين من الرأي للإجابة على هذا.في البداية، يتم الإعلان بشكل عام عن الثوابت في جافا على أنها عامة وثابتة ونهائية.فيما يلي الأسباب:

public, so that they are accessible from everywhere
static, so that they can be accessed without any instance. Since they are constants it
  makes little sense to duplicate them for every object.
final, since they should not be allowed to change

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

String myConstant = IMyInterface.CONSTANTX;

بدلاً من ذلك، سأختار بين عدة طرق مختلفة، بناءً على بعض المقايضات الصغيرة، وبالتالي يعتمد الأمر على ما تحتاجه:

1.  Use a regular enum with a default/private constructor. Most people would define 
     constants this way, IMHO.
  - drawback: cannot effectively Javadoc each constant member
  - advantage: var members are implicitly public, static, and final
  - advantage: type-safe
  - provides "a limited constructor" in a special way that only takes args which match
     predefined 'public static final' keys, thus limiting what you can pass to the
     constructor

2.  Use a altered enum WITHOUT a constructor, having all variables defined with 
     prefixed 'public static final' .
  - looks funny just having a floating semi-colon in the code
  - advantage: you can JavaDoc each variable with an explanation
  - drawback: you still have to put explicit 'public static final' before each variable
  - drawback: not type-safe
  - no 'limited constructor'

3.  Use a Class with a private constructor:
  - advantage: you can JavaDoc each variable with an explanation
  - drawback: you have to put explicit 'public static final' before each variable
  - you have the option of having a constructor to create an instance
     of the class if you want to provide additional functions related
     to your constants 
     (or just keep the constructor private)
  - drawback: not type-safe

4. Using interface:
  - advantage: you can JavaDoc each variable with an explanation
  - advantage: var members are implicitly 'public static final'
  - you are able to define default interface methods if you want to provide additional
     functions related to your constants (only if you implement the interface)
  - drawback: not type-safe

ما هي أفضل طريقة لتنفيذ الثوابت في جافا؟

أحد الأساليب التي يجب علينا تجنبها حقًا :استخدام واجهات لتحديد الثوابت.

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

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


للتبسيط، لدينا 4 طرق صالحة على نطاق واسع.

مع static final String/Integer مجال :

  • 1) استخدام فئة تعلن عن الثوابت بالداخل ولكن ليس فقط.
  • 1 متغير) إنشاء فئة مخصصة لإعلان الثوابت فقط.

مع Java 5 enum :

  • 2) الإعلان عن التعداد في فئة غرض ذات صلة (كفئة متداخلة).
  • 2) إنشاء التعداد كفئة مستقلة (محددة في ملف الفئة الخاص بها).

تلدر :ما هي الطريقة الأفضل وأين تحديد الثوابت؟

في معظم الحالات، ربما تكون طريقة التعداد أفضل من طريقة التعداد static final String/Integer طريق وشخصيا أعتقد أن static final String/Integer يجب استخدام الطريقة فقط إذا كانت لدينا أسباب وجيهة لعدم استخدام التعدادات.
وحول المكان الذي يجب أن نعلن فيه عن القيم الثابتة، الفكرة هي البحث عما إذا كان هناك فئة واحدة تمتلك تماسكًا وظيفيًا محددًا وقويًا بقيم ثابتة.إذا وجدنا مثل هذه الفئة، ينبغي لنا أن نستخدمها كحامل الثوابت.وبخلاف ذلك، يجب ألا يرتبط الثابت بفئة معينة.


static final String/ static final Integer عكس enum

إن استخدام التعدادات هو حقًا طريقة يجب أخذها بعين الاعتبار.
التعدادات لها ميزة كبيرة على String أو Integer مجال ثابت.
لقد وضعوا قيدًا أقوى على التجميع.إذا قمت بتعريف طريقة تأخذ التعداد كمعلمة، فيمكنك فقط تمرير قيمة التعداد المحددة في فئة التعداد (أو فارغة).
باستخدام String وInteger، يمكنك استبدالهما بأي قيم من النوع المتوافق وسيكون التجميع جيدًا حتى لو لم تكن القيمة ثابتة محددة في static final String/ static final Integer مجالات.

على سبيل المثال، أدناه اثنين من الثوابت المحددة في فئة ك static final String مجالات :

public class MyClass{

   public static final String ONE_CONSTANT = "value";
   public static final String ANOTHER_CONSTANT = "other value";
   . . .
}

فيما يلي طريقة تتوقع أن يكون لها أحد هذه الثوابت كمعلمة:

public void process(String constantExpected){
    ...    
}

يمكنك استدعاؤه بهذه الطريقة:

process(MyClass.ONE_CONSTANT);

أو

process(MyClass.ANOTHER_CONSTANT);

ولكن لا يوجد أي قيود على الترجمة تمنعك من استدعائها بهذه الطريقة:

process("a not defined constant value");

سيكون لديك الخطأ فقط في وقت التشغيل وفقط إذا قمت بفحص القيمة المرسلة في كل مرة.

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

على سبيل المثال، هنا قيمتان محددتان في فئة التعداد (ثابتة جدًا خارج الصندوق):

public enum MyEnum {

    ONE_CONSTANT("value"), ANOTHER_CONSTANT(" another value");

    private String value;

    MyEnum(String value) {
       this.value = value;
    }
         ...
}

فيما يلي طريقة تتوقع أن يكون لها إحدى قيم التعداد هذه كمعلمة:

public void process(MyEnum myEnum){
    ...    
}

يمكنك استدعاؤه بهذه الطريقة:

process(MyEnum.ONE_CONSTANT);

أو

process(MyEnum.ANOTHER_CONSTANT);

لكن التجميع لن يسمح لك أبدًا باستدعائه بهذه الطريقة:

process("a not defined constant value");

أين يجب أن نعلن الثوابت؟

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

على سبيل المثال، في مكتبة JDK، يتم الإعلان عن القيم الأسية وثابت pi في فئة لا تعلن فقط عن الإعلانات الثابتة (java.lang.Math).

   public final class Math {
          ...
       public static final double E = 2.7182818284590452354;
       public static final double PI = 3.14159265358979323846;
         ...
   }

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

إذا كان التطبيق الخاص بك لا يحتوي على فئة موجودة لديها تماسك وظيفي محدد وقوي للغاية مع القيم الثابتة، فإن الطرق المتغيرة 1) والمتغير 2) تبدو أكثر سهولة.
بشكل عام، لا يسهل استخدام الثوابت إذا تم الإعلان عنها في فئة واحدة تتعامل معها بينما لدينا أيضًا 3 أو 4 فئات أخرى تتعامل معها بنفس القدر ولا يبدو أن أيًا من هذه الفئات أكثر طبيعية من غيرها استضافة القيم الثابتة
هنا، من المنطقي تحديد فئة مخصصة للاحتفاظ بالقيم الثابتة فقط.
على سبيل المثال، في مكتبة JDK، يوجد java.util.concurrent.TimeUnit لم يتم الإعلان عن التعداد في فئة معينة نظرًا لعدم وجود فئة محددة واحدة فقط لـ JDK والتي تظهر على أنها الأكثر سهولة للاحتفاظ بها:

public enum TimeUnit {
    NANOSECONDS {
      .....
    },
    MICROSECONDS {
      .....
    },
    MILLISECONDS {
      .....
    },
    SECONDS {
      .....
    },
      .....
}      

أعلنت العديد من الطبقات في java.util.concurrent استخدمهم :BlockingQueue, ArrayBlockingQueue<E>, CompletableFuture, ExecutorService ، ...وفي الحقيقة لا يبدو أن أيًا منهم أكثر ملاءمة لعقد التعداد.

يمكن الإعلان عن ثابت، من أي نوع، عن طريق إنشاء خاصية غير قابلة للتغيير داخل فئة (أي متغير عضو مع final المعدل).عادة static و public يتم توفير المعدلات أيضا.

public class OfficePrinter {
    public static final String STATE = "Ready";  
}

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

public class OfficePrinter {
    public enum PrinterState { Ready, PCLoadLetter, OutOfToner, Offline };
    public static final PrinterState STATE = PrinterState.Ready;
}

تعتبر فئة الثوابت العامة فكرة سيئة.يجب تجميع الثوابت مع الفئة الأكثر ارتباطًا بها منطقيًا.

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

FWIW، من المحتمل أن تكون قيمة المهلة بالثواني عبارة عن إعداد تكوين (اقرأ من ملف خصائص أو من خلال الحقن كما في Spring) وليس ثابتًا.

ماهو الفرق

1.

public interface MyGlobalConstants {
    public static final int TIMEOUT_IN_SECS = 25;
}

2.

public class MyGlobalConstants {
    private MyGlobalConstants () {} // Prevents instantiation
    public static final int TIMEOUT_IN_SECS = 25;
}

واستخدامMyGlobalConstants.TIMEOUT_IN_SECS حيثما نحتاج إلى هذا الثابت.أعتقد أن كلاهما متماثلان.

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

ولأخذ خطوة أبعد، يمكنك وضع الثوابت المستخدمة عالميًا في الواجهة بحيث يمكن استخدامها على مستوى النظام.على سبيل المثال

public interface MyGlobalConstants {
    public static final int TIMEOUT_IN_SECS = 25;
}

لكن لا تنفذه بعد ذلك.ما عليك سوى الرجوع إليهم مباشرة في التعليمات البرمجية عبر اسم الفئة المؤهل بالكامل.

بالنسبة للثوابت، يعد Enum خيارًا أفضل IMHO.هنا مثال

الطبقة العامة ماي كلاس {

public enum myEnum {
    Option1("String1", 2), 
    Option2("String2", 2) 
    ;
    String str;
            int i;

            myEnum(String str1, int i1) { this.str = str1 ; this.i1 = i }


}

إحدى الطرق التي أقوم بها هي إنشاء فئة "عالمية" بالقيم الثابتة وإجراء استيراد ثابت في الفئات التي تحتاج إلى الوصول إلى الثابت.

static final هو ما أفضّله، سأستخدم فقط enum إذا كان العنصر معدودًا بالفعل.

أنا أستعمل static final للإعلان عن الثوابت والذهاب باستخدام تدوين التسمية ALL_CAPS.لقد رأيت عددًا لا بأس به من الحالات الواقعية حيث يتم تجميع جميع الثوابت معًا في واجهة.وصفت بعض المنشورات ذلك بأنه ممارسة سيئة، ويرجع ذلك أساسًا إلى أن هذا ليس الغرض من الواجهة.يجب أن تقوم الواجهة بتنفيذ العقد ويجب ألا تكون مكانًا لوضع ثوابت غير ذات صلة.يعد تجميعها معًا في فئة لا يمكن إنشاء مثيل لها (من خلال مُنشئ خاص) أمرًا جيدًا أيضًا إذا كانت الدلالات الثابتة لا تنتمي إلى فئة (فئات) معينة.أضع دائمًا ثابتًا في الفصل الدراسي الأكثر ارتباطًا به، لأن ذلك منطقي ويمكن صيانته بسهولة.

تعد التعدادات خيارًا جيدًا لتمثيل نطاق من القيم، ولكن إذا كنت تقوم بتخزين ثوابت مستقلة مع التركيز على القيمة المطلقة (على سبيل المثال،TIMEOUT = 100 مللي ثانية) يمكنك فقط الانتقال إلى static final يقترب.

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

@Retention(SOURCE)
@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST,NAVIGATION_MODE_TABS})
public @interface NavigationMode {}
public static final int NAVIGATION_MODE_STANDARD = 0;
public static final int NAVIGATION_MODE_LIST = 1;
public static final int NAVIGATION_MODE_TABS = 2;
...
public abstract void setNavigationMode(@NavigationMode int mode);
@NavigationMode
public abstract int getNavigationMode();

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

إنها عادة سيئة وممارسة مزعجة بشكل رهيب لنقتبس من جوشوا بلوخ دون فهم الأصولية الأساسية.

أنا لم أقرأ أي شيء لجوشوا بلوخ، كذلك

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

كما هو الحال في أصولية الكتاب المقدس، يمكن تلخيص كل قوانين الكتاب المقدس

  • أحب الهوية الأساسية من كل قلبك ومن كل عقلك
  • أحب قريبك كنفسك

وهكذا يمكن تلخيص أصولية هندسة البرمجيات بالمثل

  • كرّس نفسك للأساسيات الأساسية بكل ما لديك من قوة وعقل
  • وكرس جهودك نحو التميز لزملائك المبرمجين كما تفعل لنفسك.

وأيضًا، هناك نتيجة طبيعية قوية ومعقولة بين الدوائر الأصولية الكتابية

  • اولا احب نفسك.لأنه إذا كنت لا تحب نفسك كثيرًا، فإن مفهوم "أحب جارك كنفسك" ليس له وزن كبير، لأن "مدى حبك لنفسك" هو خط المرجع الذي فوقه تحب الآخرين.

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

القوانين الأساسية للبرمجة البرمجية

  • الكسل هو فضيلة المبرمج الجيد
  • عليك أن تجعل حياتك البرمجية سهلة، وكسولة، وبالتالي فعالة قدر الإمكان
  • عليك أن تجعل عواقب وأحشاء برمجتك سهلة، وكسولة، وبالتالي فعالة قدر الإمكان للمبرمجين الجيران الذين يعملون معك ويلتقطون أحشاء برمجتك.

ثوابت نمط الواجهة عادة سيئة ؟؟؟

تحت أي قوانين البرمجة الفعالة والمسؤولة بشكل أساسي يقع هذا المرسوم الديني ضمنها؟

ما عليك سوى قراءة مقالة ويكيبيديا حول ثوابت نمط الواجهة (https://en.wikipedia.org/wiki/Constant_interface) ، والأعذار السخيفة التي تنص عليها ضد ثوابت نمط الواجهة.

  • Whatif-لا IDE؟من على وجه الأرض كمبرمج برمجيات لن يستخدم IDE؟معظمنا مبرمجون يفضلون عدم الاضطرار إلى إثبات امتلاكهم لنزعة البقاء الرجولية من خلال تجنب استخدام IDE.

    • أيضًا - انتظر ثانيًا أنصار البرمجة الوظيفية الدقيقة كوسيلة لعدم الحاجة إلى IDE.انتظر حتى تقرأ شرحي حول تطبيع نموذج البيانات.
  • هل يلوث مساحة الاسم بمتغيرات غير مستخدمة ضمن النطاق الحالي؟ومن الممكن أن يكون أصحاب هذا الرأي

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

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

    • لماذا تريد الانخراط في هذا النمط من البرمجة باعتباره مصدر رزقك المستمر؟يا إلهي، لماذا تكرس نفسك لمثل هذه العادة البرمجية السيئة والمتناقضة؟

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

لا يهم ما هي النوايا الأصلية والحالات العقلية للآباء المؤسسين الذين صاغوا دستور الولايات المتحدة.يمكننا مناقشة النوايا الأصلية للآباء المؤسسين، لكن كل ما يهمني هو البيانات المكتوبة لدستور الولايات المتحدة.وتقع على عاتق كل مواطن أمريكي مسؤولية استغلال الأصولية الأدبية المكتوبة، وليس النوايا التأسيسية غير المكتوبة لدستور الولايات المتحدة.

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

الأساس هو تطبيع نموذج البيانات

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

يجب علينا أولاً تحديد وتطبيع نموذج البيانات لمجموعة من العمليات.وعندما يكون لدينا نموذج بيانات متماسك، عندها فقط يمكننا استخدام تدفق العملية لمكوناته لتحديد السلوك الوظيفي وكتل العمليات في مجال أو مجال من التطبيقات.وعندها فقط يمكننا تحديد واجهة برمجة التطبيقات (API) لكل عملية وظيفية.

حتى جوانب تطبيع البيانات كما اقترحتها EF Codd تواجه الآن تحديات شديدة وتحديات شديدة.على سبيل المثالتم انتقاد بيانه على 1NF باعتباره غامضًا ومنحرفًا ومفرطًا في التبسيط، كما هو الحال مع بقية تصريحاته خاصة في ظهور خدمات البيانات الحديثة وتكنولوجيا الريبو والنقل.IMO، يجب التخلص تمامًا من عبارات EF Codd وتصميم مجموعة جديدة من العبارات الأكثر معقولية من الناحية الرياضية.

إن العيب الصارخ في إي إف كود وسبب عدم توافقه مع الفهم البشري الفعال هو اعتقاده بأن البيانات متعددة الأبعاد القابلة للتغيير والتي يمكن إدراكها إنسانيًا يمكن إدراكها بكفاءة من خلال مجموعة من التعيينات المجزأة ثنائية الأبعاد.

أساسيات تطبيع البيانات

ما فشل EF Codd في التعبير عنه.

داخل كل نموذج بيانات متماسك، هذا هو الترتيب المتدرج المتسلسل لتماسك نموذج البيانات المطلوب تحقيقه.

  1. وحدة وهوية مثيلات البيانات.
    • تصميم تفاصيل كل مكون من مكونات البيانات، حيث تكون تفاصيلها عند مستوى يمكن من خلاله تحديد كل مثيل للمكون واسترجاعه بشكل فريد.
    • عدم وجود مثيل التعرج.أي أنه لا توجد وسيلة يمكن من خلالها أن ينتج عن التعريف أكثر من مثيل واحد للمكون.
  2. غياب المثال الحديث المتبادل.لا توجد ضرورة لاستخدام واحد أو أكثر من مثيلات المكون للمساهمة في تحديد مثيل المكون.
  3. وحدة وهوية مكونات/أبعاد البيانات.
    • وجود إزالة التعرجات للمكونات.يجب أن يكون هناك تعريف واحد يمكن من خلاله تحديد المكون/البعد بشكل فريد.وهو التعريف الأساسي للمكون؛
    • عندما لا يؤدي التعريف الأساسي إلى الكشف عن الأبعاد الفرعية أو المكونات الأعضاء التي لا تشكل جزءًا من المكون المقصود؛
  4. وسائل فريدة لتوزيع المكونات.يجب أن يكون هناك تعريف واحد فقط لإزالة التعرجات للمكون.
  5. توجد واجهة تعريف واحدة أو عقد واحد فقط لتحديد المكون الأصلي في العلاقة الهرمية للمكونات.
  6. غياب الحديث المتبادل للمكونات.لا توجد ضرورة لاستخدام عضو في مكون آخر للمساهمة في التحديد النهائي للمكون.
    • في مثل هذه العلاقة بين الوالدين والطفل، يجب ألا يعتمد التعريف التعريفي للوالد على جزء من مجموعة مكونات الأعضاء للطفل.يجب أن يكون أحد مكونات هوية أحد الوالدين هو هوية الطفل الكاملة دون اللجوء إلى الإشارة إلى أي من أطفال الطفل أو جميعهم.
  7. استباق المظاهر ثنائية الوسائط أو متعددة الوسائط لنموذج البيانات.
    • عندما يكون هناك تعريفان مرشحان لمكون ما، فهذه علامة واضحة على وجود نموذجين مختلفين للبيانات يتم خلطهما كنموذج واحد.وهذا يعني أن هناك عدم ترابط على مستوى نموذج البيانات، أو على المستوى الميداني.
    • يجب أن يستخدم مجال التطبيقات نموذج بيانات واحدًا فقط بشكل متماسك.
  8. كشف وتحديد طفرة المكون.ما لم تقم بإجراء تحليل مكون إحصائي للبيانات الضخمة، فمن المحتمل أنك لا ترى، أو ترى الحاجة إلى علاج، طفرة المكونات.
    • قد يكون لنموذج البيانات بعض مكوناته التي تتغير بشكل دوري أو تدريجي.
    • قد يكون الوضع عبارة عن دوران الأعضاء أو دوران التبديل.
    • يمكن أن تكون طفرة دوران الأعضاء عبارة عن تبادل متميز للمكونات الفرعية بين المكونات.أو حيث يجب تحديد مكونات جديدة تمامًا.
    • قد تظهر الطفرة الانتقالية كعضو بعدي يتحول إلى سمة، والعكس صحيح.
    • يجب تحديد كل دورة طفرة على أنها نموذج بيانات مميز.
  9. إصدار كل طفرة.بحيث يمكنك سحب إصدار سابق من نموذج البيانات، عندما تنشأ الحاجة إلى معالجة طفرة عمرها 8 سنوات في نموذج البيانات.

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

هل ما زلنا نتساءل عما إذا كان بإمكاننا استخدام ثوابت الواجهة؟حقًا ؟

هناك قضايا تطبيع البيانات على المحك أكثر أهمية من هذا السؤال الدنيوي.إذا لم تحل هذه المشكلات، فإن الارتباك الذي تعتقد أن ثوابت الواجهة تسببه لا يعد شيئًا نسبيًا.لا شيء.

من تسوية نموذج البيانات، يمكنك تحديد المكونات كمتغيرات، كخصائص، كثوابت واجهة العقد.

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

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

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

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

فلماذا لا يتم نشر عقد نموذج البيانات؟أعني أنه إذا كان بإمكانك إدارتها وتطبيعها بشكل متماسك، فلماذا لا؟...

public interface CustomerService {
  public interface Label{
    char AssignmentCharacter = ':';
    public interface Address{
      String Street = "Street";
      String Unit= "Unit/Suite";
      String Municipal = "City";
      String County = "County";
      String Provincial = "State";
      String PostalCode = "Zip"
    }

    public interface Person {
      public interface NameParts{
        String Given = "First/Given name"
        String Auxiliary = "Middle initial"
        String Family = "Last name"
      }
    }
  }
}

يمكنني الآن الإشارة إلى التصنيفات المتعاقد عليها لتطبيقاتي بطريقة مثل

CustomerService.Label.Address.Street
CustomerService.Label.Person.NameParts.Family

هذا يخلط بين محتويات ملف الجرة؟باعتباري مبرمج جافا، لا أهتم ببنية الجرة.

يمثل هذا تعقيدًا لمبادلة وقت التشغيل بدوافع osgi؟تعد Osgi وسيلة فعالة للغاية للسماح للمبرمجين بالاستمرار في عاداتهم السيئة.هناك بدائل أفضل من osgi.

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

public class PurchaseRequest {
  private interface Constants{
    String INTERESTINGName = "Interesting Name";
    String OFFICIALLanguage = "Official Language"
    int MAXNames = 9;
  }
}

وربما حتى هذا:

public interface PurchaseOrderConstants {
  public interface Properties{
    default String InterestingName(){
       return something();
    }
    String OFFICIALLanguage = "Official Language"
    int MAXNames = 9;
  }
}

المشكلة الوحيدة في ثوابت الواجهة التي تستحق الاهتمام هي عند تنفيذ الواجهة.

أليس هذا هو "القصد الأصلي" للواجهات؟وكأنني أهتم بـ "النية الأصلية" للآباء المؤسسين في صياغة دستور الولايات المتحدة، بدلاً من الاهتمام بكيفية تفسير المحكمة العليا للرسائل المكتوبة من دستور الولايات المتحدة ؟؟؟

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

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