الكتابة "الأكثر مرونة" في C# عن طريق إسقاط شجرة الميراث

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

سؤال

والسؤال الذي أريد أن أطرحه هو بالتالي:

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

الآن، مثال لماذا أعتقد أنه يمكن استخدامه من أجل الخير.

لقد نفذت مؤخرا التشفير من بروتوكول BitTorrent شركة#.مشكلة بسيطة بما فيه الكفاية، كيفية تمثيل البيانات.اخترت أن أفعل ذلك بهذه الطريقة،

لدينا abstract BItem فئة، والتي توفر بعض الوظائف الأساسية، بما في ذلك static BItem Decode(string) يتم استخدامه لفك تشفير سلسلة Bencoded في البنية الضرورية.

هناك أيضًا أربع فئات مشتقة، BString, BInteger, BList و BDictionary, ، يمثل أنواع البيانات الأربعة المختلفة التي سيتم تشفيرها.الآن هنا هو الجزء صعبة. BList و BDictionary يملك this[int] و this[string] الوصول على التوالي للسماح بالوصول إلى الصفات الشبيهة بالمصفوفة لأنواع البيانات هذه.

الجزء المروع المحتمل يأتي الآن:

BDictionary torrent = (BDictionary) BItem.DecodeFile("my.torrent");
int filelength = (BInteger)((BDictionary)((BList)((BDictionary)
             torrent["info"])["files"])[0])["length"];

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

public BItem this[int index]
{
    get { return ((BList)this)[index]; }
}
public BItem this[string index]
{
    get { return ((BDictionary)this)[index]; }
}

الآن يمكننا إعادة كتابة هذا الكود القديم على النحو التالي:

BDictionary torrent = (BDictionary)BItem.DecodeFile("my.torrent");
int filelength = (BInteger)torrent["info"]["files"][0]["length"];

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

يحرر:ردًا على بعض الإجابات الواردة، فأنت خارج المسار تمامًا بالنسبة لهذا السؤال تحديدًا نظرًا لأن البنية متغيرة، على سبيل المثال مثالي torrent["info"]["files"][0]["length"] صحيح، ولكن الأمر كذلك torrent["announce-list"][0][0], وكلاهما سيكون موجودًا في 90% من ملفات التورنت المتوفرة.الأدوية العامة ليست هي الحل الأمثل، مع هذه المشكلة على الأقل :(.انقر للوصول إلى المواصفات التي قمت بربطها، فهي عبارة عن 4 نقاط صغيرة فقط.

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

المحلول

أعتقد أنني سأجعل موصلات this[int] وthis[string] افتراضية وأتجاوزها في BList/BDictionary.يجب أن تقوم الفئات التي لا يكون لها معنى للوصول إلى NotSupportedException() (ربما عن طريق وجود تطبيق افتراضي في BItem).

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

 (BInteger)torrent["info"][0]["files"]["length"];

عن طريق الخطأ.

نصائح أخرى

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

إذا كان طول الملف هو الشيء الذي تسترده كثيرًا، فلماذا لا تقوم بتطبيق خاصية في فئة BDictionary (؟)...بحيث يصبح الكود الخاص بك:

BDictionary torrent = BItem.DecodeFile("my.torrent");
int filelength = torrent.FileLength;

بهذه الطريقة يتم إخفاء تفاصيل التنفيذ عن المستخدم.

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

abstract class BCollection : BItem {

      public BItem this[int index] {get;}
      public BItem this[string index] {get;}
}

وجعل BList وBDictionary يرثان من BCollection.أو يمكنك بذل جهد إضافي وجعل BCollection فئة عامة.

توصيتي هي تقديم المزيد من التجريدات.أجد أنه من المربك أن يحتوي BItem على DecodeFile() الذي يُرجع BDictionary.قد يكون هذا أمرًا معقولًا في مجال التورنت، لا أعرف.

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

BFile torrent = BFile.DecodeFile("my.torrent");
int filelength = torrent.Length;

هل فكرت في تحليل "مسار" بسيط حتى تتمكن من كتابته بهذه الطريقة:

BDictionary torrent = BItem.DecodeFile("my.torrent");
int filelength = (int)torrent.Fetch("info.files.0.length");

ربما ليست الطريقة الأفضل، لكن سهولة القراءة تزيد (قليلاً)

  • إذا كان لديك سيطرة كاملة على قاعدة التعليمات البرمجية الخاصة بك وعملية التفكير الخاصة بك، فافعل ذلك بكل الوسائل.
  • إذا لم يكن الأمر كذلك، فسوف تندم على ذلك في اليوم الذي يقوم فيه شخص جديد بإدخال اشتقاق BItem لم تره يدخل لك BList أو BDictionary.

إذا كان عليك القيام بذلك، فقم على الأقل بتغليفه (التحكم في الوصول إلى القائمة) في فئة تحتوي على توقيعات الطريقة المكتوبة بقوة.

BString GetString(BInteger);
SetString(BInteger, BString);

قبول وإرجاع BStrings على الرغم من قيامك بتخزينها داخليًا في قائمة BList من BItems. (دعني أقسم قبل أن أحصل على 2 ب أو لا 2 ب)

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

إذا قمت بتقديم الأدوية العامة، يمكنك تجنب الصب.

class DecodedTorrent : BDictionary<BDictionary<BList<BDictionary<BInteger>>>>
{
}

DecodedTorrent torrent = BItem.DecodeFile("mytorrent");
int x = torrent["info"]["files"][0]["length"];

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

هل لي فقط

BDictionary torrent = BItem.DecodeFile("my.torrent");int filelength = (BInteger)((BDictionary)((BList)((BDictionary)             torrent["info"])["files"])[0])["length"];

لا تحتاج إلى إعلان BDictionary cast "torrent" على أنه BDictionary

public BItem this[int index]{&nbsp; &nbsp; get { return ((BList)this)[index]; }}public BItem this[string index]{&nbsp; &nbsp; get { return ((BDictionary)this)[index]; }}

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

يجب أن يكون الكود المعاد كتابته

BDictionary torrent = BItem.DecodeFile("my.torrent");int filelength = (BInteger)((BList)((BDictionary)torrent["info"]["files"])[0])["length"];

وهو أمر سيء مثل الدفعة الأولى

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