سؤال

getEmployeeNameByBatchId(int معرف الدفعة)
getEmployeeNameBySSN (كائن SSN)
getEmployeeNameByEmailId (معرف البريد الإلكتروني للسلسلة)
الحصول على اسم الموظف حسب حساب الراتب (حساب الراتب)

أو

getEmployeeName(int typeOfIdentifier, byte[] identifier) ​​-> في هذه الطرق، يخبر typeOfIdentifier ما إذا كان المعرف هو BatchID/SSN/emailID/salaryAccount

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

ستكون هذه الطرق موجودة في Servlet وسيتم إجراء المكالمات من واجهة برمجة التطبيقات (API) التي سيتم توفيرها للعملاء.

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

المحلول

لماذا لا تفرط في تحميل طريقة getEmployeeName(؟؟)؟

getEmployeeName(int BatchID)
getEmployeeName (كائن SSN)(فكرة سيئة)
getEmployeeName (سلسلة البريد الإلكتروني)
إلخ.

يبدو نهج "كثير" جيدًا بالنسبة لي.

نصائح أخرى

يمكنك استخدام شيء من هذا القبيل:

interface Employee{
    public String getName();
    int getBatchId();
}
interface Filter{
    boolean matches(Employee e);
}
public Filter byName(final String name){
    return new Filter(){
        public boolean matches(Employee e) {
            return e.getName().equals(name);
        }
    };
}
public Filter byBatchId(final int id){
    return new Filter(){
        public boolean matches(Employee e) {
            return e.getBatchId() == id;
        }
    };
}
public Employee findEmployee(Filter sel){
    List<Employee> allEmployees = null;
    for (Employee e:allEmployees)
        if (sel.matches(e))
            return e;
    return null;
}
public void usage(){
    findEmployee(byName("Gustav"));
    findEmployee(byBatchId(5));
}

إذا قمت بالتصفية حسب استعلام SQL، فستستخدم Filter واجهة لإنشاء جملة WHERE.

الشيء الجيد في هذا الأسلوب هو أنه يمكنك الجمع بين مرشحين بسهولة باستخدام:

public Filter and(final Filter f1,final Filter f2){
    return new Filter(){
        public boolean matches(Employee e) {
            return f1.matches(e) && f2.matches(e);
        }
    };
}

واستخدامها مثل هذا:

findEmployee(and(byName("Gustav"),byBatchId(5)));

ما تحصل عليه يشبه Criteria API في السبات.

سأتبع النهج "الكثير".يبدو الأمر أكثر بديهية بالنسبة لي وأقل عرضة للخطأ.

لا أحب getXByY() - قد يكون ذلك رائعًا في PHP، لكني لا أحبه في Java (ymmv).

سأختار التحميل الزائد، إلا إذا كان لديك خصائص من نفس نوع البيانات.في هذه الحالة، سأفعل شيئًا مشابهًا لخيارك الثاني، ولكن بدلاً من استخدام ints، سأستخدم Enum لضمان سلامة الكتابة ووضوحها.وبدلاً من byte[]، سأستخدم Object (بسبب العلبة التلقائية، وهذا يعمل أيضًا مع البدائيين).

تعتبر الطرق مثالًا مثاليًا لاستخدام التحميل الزائد.

getEmployeeName(int batchID)
getEmployeeName(Object SSN)
getEmployeeName(String emailID)
getEmployeeName(SalaryAccount salaryAccount)

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

الخيار الأول بلا شككن واضحا.سوف يساعد بشكل كبير في قابلية الصيانة وليس هناك أي جانب سلبي حقًا.

@ ستيفان:من الصعب زيادة التحميل على حالة كهذه (بشكل عام) لأن أنواع المعلمات قد لا تكون تمييزية، على سبيل المثال،

  • getEmployeeNameByBatchId(int BatchId)
  • getEmployeeNameByRoomNumber(int RoomNumber)

راجع أيضًا الطريقتين getEmployeeNameBySSN و getEmployeeNameByEmailId في النشر الأصلي.

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

في بعض الأحيان قد يكون من المناسب أكثر استخدام نمط المواصفات.

على سبيل المثال:GetEmployee(مواصفات ISpecification<Employee>)

ومن ثم ابدأ بتحديد مواصفاتك...

مواصفات الاسم :المواصفات<الموظف>
{
اسم السلسلة الخاصة؛
public NameSpecification(string name) { this.name = name;}
public bool IsSatisFiedBy(Employeeemployee) {return member.Name == this.name;}
}

NameSpecification spec = new NameSpecification("تيم");
الموظف تيم = MyService.GetEmployee(spec);

سأستخدم الخيار الأول، أو أحمله بشكل زائد في هذه الحالة، نظرًا لأن لديك 4 توقيعات مختلفة للمعلمات.ومع ذلك، فإن التحديد الدقيق يساعد في فهم الكود بعد 3 أشهر من الآن.

هل المنطق داخل كل من هذه الأساليب هو نفسه إلى حد كبير؟

إذا كان الأمر كذلك، فإن الطريقة المفردة ذات معلمة المعرف قد تكون أكثر منطقية (رمز بسيط ومتكرر).

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

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

ملحوظة:راجع للشغل، قد يكون استخدام التعدادات شيئًا يجب مراعاته في بعض الحالات.

في حالة تافهة مثل هذه، سأختار التحميل الزائد.إنه:

getEmployeeName( int batchID );
getEmployeeName( Object SSN );

etc.

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

لا أستطيع أن أرى لماذا قد أستخدم هذا على الإطلاق

getEmployeeName(int typeOfIdentifier, byte[] identifier)

لأنه يتطلب من المستدعي والمتصل إرسال القيمة بناءً على typeOfIdentifier.تصميم سيء.

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

"اختر الاسم من..."
"اختر رقم الضمان الاجتماعي من..."
"اختر البريد الإلكتروني من ..."
ضد.
"اختر من ..."

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

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

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

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

  • getEmployeeName(int BatchID)
  • getEmployeeName (سلسلة البريد الإلكتروني)
  • إلخ.

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

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

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

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

للتلخيص، استخدم اسم طريقة فريدًا لكل طريقة، فالتحميل الزائد يمكن أن يسبب مشاكل على المدى الطويل فقط.

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

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

ربما يكون الأول هو الأفضل في Java، مع الأخذ في الاعتبار أنه آمن للكتابة (على عكس الآخر).بالإضافة إلى ذلك، بالنسبة للأنواع "العادية"، يبدو أن الحل الثاني يوفر فقط استخدامًا مرهقًا للمستخدم.ومع ذلك، نظرًا لأنك تستخدم "الكائن" كنوع لـ SSN (الذي له معنى دلالي يتجاوز "الكائن")، فمن المحتمل أنك لن تفلت من هذا النوع من واجهة برمجة التطبيقات (API).

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

ضع جميع خياراتك في التعداد، وسيكون لديك شيء مثل ما يلي

GetEmployeeName(Enum identifier)
{
    switch (identifier)
    case eBatchID:
    {
        // Do stuff
    }
    case eSSN:
    {
    }
    case eEmailId:
    {
    }
    case eSalary:
    {
    }
    default:
    {
        // No match
        return 0;
    }
}

enum Identifier
{
    eBatchID,
    eSSN,
    eEmailID,
    eSalary
}

أنت تفكر في C/C++.

استخدم الكائنات بدلاً من بايت المعرف (أو int).

يا سيدي، أسلوب التحميل الزائد أفضل واستخدام SSN كمفتاح أساسي ليس جيدًا

public ??? getEmployeeName(Object obj){

if (obj instanceof Integer){

  ...

} else if (obj instanceof String){

...

} else if .... // and so on


} else throw SomeMeaningFullRuntimeException()

return employeeName
}

أعتقد أنه من الأفضل استخدام الاستثناءات غير المحددة للإشارة إلى الإدخال غير الصحيح.

قم بتوثيقه حتى يعرف العميل الأشياء التي يتوقعها.أو قم بإنشاء الأغلفة الخاصة بك.أفضّل الخيار الأول.

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