سؤال

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

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

ربما يكون exampleof مشروعًا تمامًا في هذه الحالة (تعرف الكائنات عن نفسها) ولكني ما زلت أبحث عن الطرق الممكنة لتجنب ذلك.أيه أفكار؟

مثال على الكود الزائف:

betweenXandY = create new between class(x, y)
greaterThanZ = create new greaterThan class(z)
greaterThanZ.matchCompareCriteria(betweenXandY)

إذا كانت X وY أكبر من Z فستعود صحيحة.

يحرر:

1) مثيل هو ما أراه، في الوقت الحالي، حسب الحاجة في طريقة matchCompareCriteria.أود التخلص منه

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

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

المحلول

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

وعادة في OO هناك إيفاد واحد - استدعاء أسلوب على كائن يسبب تنفيذ هذا الكائن من طريقة لتنفيذ

.

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

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

class OperatorBase
{
    bool matchCompareCriteria(var other)
    {
        var comparisonMethod = this.GetMethod("matchCompareCriteria" + other.TypeName);
        if (comparisonMethod == null)
            return false;

        return comparisonMethod(other);
    }
}

وهنا أنا تخيل أن اللغة لديه أسلوب مضمنة في كل فئة تسمى GetMethod التي تسمح لي للبحث عن طريقة بالاسم، وأيضا خاصية TypeName على كل كائن أن يحصل لي اسم من نوع الكائن. إذا كان الأمر كذلك فئة أخرى هي GreaterThan، وفئة مشتقة لديه طريقة تسمى matchCompareCriteriaGreaterThan، وسوف ندعو هذه الطريقة:

class SomeOperator : Base
{
    bool matchCompareCriteriaGreaterThan(var other)
    {
        // 'other' is definitely a GreaterThan, no need to check
    }
}

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

في لغة كتابتها بشكل ثابت الذي يدعم طريقة الحمولة الزائدة عن طريق نوع الحجة، يمكننا تجنب الحاجة إلى ابتكار اصطلاح تسمية متسلسلة - على سبيل المثال، ومن هنا في C #:

class OperatorBase
{
    public bool CompareWith(object other)
    {
        var compare = GetType().GetMethod("CompareWithType", new[] { other.GetType() });
        if (compare == null)
            return false;

        return (bool)compare.Invoke(this, new[] { other });
    }
}

class GreaterThan : OperatorBase { }
class LessThan : OperatorBase { }

class WithinRange : OperatorBase
{
    // Just write whatever versions of CompareWithType you need.

    public bool CompareWithType(GreaterThan gt)
    {
        return true;
    }

    public bool CompareWithType(LessThan gt)
    {
        return true;
    }
}

class Program
{
    static void Main(string[] args)
    {
        GreaterThan gt = new GreaterThan();
        WithinRange wr = new WithinRange();

        Console.WriteLine(wr.CompareWith(gt));
    }
}

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

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

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

ما النهج الحق يتوقف على مدى العديد من أنواع أنت من المحتمل أن ينتهي في النموذج الخاص بك.

نصائح أخرى

ومنذ لك مرجع instanceof، أفترض أننا نعمل في جاوة هنا. هذا قد تمكنك من الاستفادة من الحمولة الزائدة. النظر في واجهة دعا SomeInterface، التي لديها أسلوب واحد:

public interface SomeInterface {
    public boolean test (SomeInterface s);
}

والآن، نعرف اثنين (يسمى بذكاء) الفئات التي تقوم بتنفيذ SomeInterface: Some1 وSome2. Some2 يبعث على السأم: test دوما بإرجاع كاذبة. لكن Some1 يتجاوز وظيفة test عندما تعطى Some2:

public class Some1 implements SomeInterface {
    public boolean test (SomeInterface s) {
        return false;
    }

    public boolean test (Some2 s) {
        return true;
    }
}

وهذا يتيح لنا تجنب الاضطرار خط بعد خط إذا كانت تصريحات للقيام نوع التحقق. ولكن هناك تحذير. النظر في هذا الرمز:

Some1 s1 = new Some1 ();
Some2 s2 = new Some2 ();
SomeInterface inter = new Some2 ();

System.out.println(s1.test(s2));     // true
System.out.println(s2.test(s1));     // false
System.out.println(s1.test(inter));  // false

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

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

وإعادة تصميم في محله، ولكن من دون الكثير من المعلومات، وأنا لا يمكن أن تعطيك دفعة جيدة particluarly في الاتجاه الصحيح.

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

والطبقة معايير ستحدد طريقة matchCompareCriteria التي تقبل المعايير. فإن المنطق الفعلي يقيم في الطبقات الفرعية.

أنت تبحث عن أي نمط تصميم استراتيجية أو نمط تصميم القالب.

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

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

خاتمة:استخدام instanceof على ما يرام في هذه الحالة.

هنا أطول شرط من Steve Yegge، والذي يشرح بشكل أفضل، على ما أعتقد، باستخدام مثال بسيط ومباشر.أعتقد أن هذا يمثل حلاً رائعًا لمشكلتك.

يتذكر: تعدد الأشكال أمر جيد، إلا عندما لا يكون كذلك. :)

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

بالحديث عن ذلك، ربما تريد إعادة تسمية "matchCompareCriteria" إلى شيء يعبر عن النية بشكل أفضل قليلاً.

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