مقدمة
في الآونة الأخيرة ، أثناء عملية التعلم ، اكتشفت مشكلة. لا يمكن لفئات التجريد بناء الكائن من خلال جديد دون تنفيذ جميع الأساليب المجردة ، ولكن يمكن أن يكون للأساليب المجردة أساليب البناء الخاصة بها. هذا أربكني. نظرًا لوجود طريقة بناء ولا يمكن إنشاؤها من خلال جديد ، هل يمكن إنشاء فصول تجريدية عندما لا تصبح فصولًا ملموسة؟
في Java ، لا يمكن إنشاء فصول مجردة مباشرة. ومع ذلك ، فإن هذه الميزة من الفصول المجردة غالبا ما تصبح عقبة مزعجة. على سبيل المثال ، إذا كنت أرغب في استخدام وكيل ديناميكي لإعطاء فئة مجردة القدرة على تنفيذ أساليب مجردة ، فستكون هناك صعوبات: 1. يمكن للوكالة الديناميكية فقط إنشاء كائن وكيل يقوم بتطبيق الواجهة ، ولكن ليس كائنًا يرث الفئة التجريدية. بالنسبة لهذا JVM القياسي ، هناك بعض التطبيقات ، مثل Javassist ، والتي يمكن استخدامها لإنجاز هذا باستخدام أدوات Bytecode (ProxyFactory).
إذا كنت ترغب في إنشاء كائن فئة مجردة في Android ، فقد يكون لديك فقط new ClassName() {} أو موروثة. ومع ذلك ، لا يمكن تشغيل كلتا الطريقتين مباشرة بواسطة كائنات الفئة الخاصة بهم ، مما يؤدي إلى بعض المشكلات التي لا يمكنها تحقيق القدرات المجردة التي نحتاجها.
فيما يلي وصف مفصل للمشهد المذكور في الفقرة الأولى:
أولاً ، هناك ملف واجهة محدد على النحو التالي (يمكن للأصدقاء على دراية بنظام Android أن يروا أن هذه واجهة تكوين API مقدمة إلى التعديل التحديثي لإنشاء كائنات وكيل):
الواجهة العامة realapi {get ("api1") يمكن ملاحظتها <string> api1 () ؛ get ("api2") يمكن ملاحظتها <string> api2 () ؛ get ("api3") يمكن ملاحظتها <string> api3 () ؛ //... أساليب أخرى}بعد ذلك ، اكتب فئة مجردة لتنفيذ واحدة فقط من طرق الواجهة (المستخدمة لمحاكاة بيانات الواجهة):
mockapipubublic class class mockapi تنفذ realapi {string <string> api3 () {return obsertable.just ("Dock Data") ؛ }}ثم نحتاج إلى الحصول على أداة ، مثل Mockmanager ، التي تجمع بين كائن Realapi الحالي وفئة Mockapi لبناء كائن مختلط. عند تنفيذ الأساليب المحددة بالفعل في Mockapi ، سيتم تنفيذها مباشرة. عندما لا تحدد Mockapi الطريقة ، فإنها ستسمي طريقة Realapi. طريقة الاتصال تقريبًا:
realapi API = mockmanager.build (realapi ، mockapi.class) ؛
من خلال Javassist ، من السهل جدًا إكمال الوظيفة أعلاه. قم بإنشاء كائن proxyfactory ، وضبط الفئة الفائقة على Mockapi ، ثم قم بتصفية الطريقة التجريدية ، وقم بتعيين معالج الأسلوب للاتصال بكائن Realapi بنفس الاسم والمعلمة. لن يتم إعطاء تنفيذ الكود هنا.
ولكن على Android ، سيتم طرح طريقة Javassist
سبب: java.lang.unsupportedOperationException: لا يمكن تحميل هذا النوع من ملف الفئة على java.lang.classloader.defineclass (classloader.java:520) في java.lang.reflect.method.invoke (الطريقة الأصلية) في javassist.util.proxy.factoryhelper.toclass2 (FactoryHelper.java:182)
استثناءات مماثلة. ربما يكون السبب هو أن تنفيذ ومعايير الأجهزة الافتراضية على Android مختلفة قليلاً ، لذلك هنا نقول الاتجاه إلى اتجاه آخر من معالج توليد الكود الديناميكي.
إذا كنت تستخدم معالج التعليقات التوضيحية لتنفيذها ، فإن الفكرة أبسط بكثير ، لكن العملية لا تزال متعرجًا بعض الشيء:
حدد أولاً شرحًا للاحتفال بالفئة التجريدية التي يجب إنشاؤها
target (elementType.type)@موثقة@attreence (entrentionpolicy.source) public interface mockapi {} يحصل المعالج على كائن العنصر للفئة استنادًا إلى التعليق التوضيحي ، وهو كائن يشبه الفصل. نظرًا لأن الفئة غير موجودة بعد في مرحلة التجميع ، فمن المستحيل الحصول على كائن الفصل المطلوب في وقت التشغيل باستخدام Class.forName . ومع ذلك ، فإن العنصر يوفر طرقًا مشابهة للانعكاس الفئة ، وهناك أيضًا اختلافات مثل typeElement و ExecutableElement. ما هي الأساليب المجردة للفئة المجردة المشروحة باستخدام كائن العنصر لتحليل فئة التجريدية المشروحة ، وإنشاء فئة تنفيذ (غير مجردة) ترث الفصل ، وتنفيذ جميع الأساليب المجردة في الفصل. نظرًا لأن هذه الأساليب المجردة لن يتم استخدامها بالفعل ، فهي بحاجة فقط إلى أن تكون قادرة على التجميع والتمرير. الطريقة التي اخترتها هي أن كل طريقة هيئة يلقي استثناء ، مما يدفع أن الطريقة هي طريقة مجردة ولا يمكن استدعاؤها مباشرة. يمكن أن تستخدم طريقة إنشاء رمز بعض الأدوات لتبسيط العمل ، مثل Autoprocessor و Javapoet ، والتي تنفذ على وجه التحديد رمز المشروع في نهاية النص المرجعي. الرمز الذي تم إنشاؤه يشبه هذا:
// تم تسمية اسم الفصل الذي تم إنشاؤه مع لاحقة اسم الفئة الأصلي + "$ INM" لتجنب النزاعات مع أسماء الفصول الدراسية الأخرى. يستخدم هذا القيد أيضًا لتعكس الفئة العامة الفئة النهائية mockapi $ $ تمتد mockapi {Override Publicable <String> API1 () {رمي جديد غير مقبل aluvalstateException ("API1 () طريقة تجريدية!") ؛ } Override publicable <string> api2 () {رمي جديد alficalstateException ("api2 () طريقة مجردة!") ؛ }}تعكس فئة التنفيذ استنادًا إلى اسم الفئة للفئة التجريدية ، ثم قم ببناء كائن تنفيذ بناءً على الانعكاس عن طريق استدعاء طريقة مُنشئه.
// احصل على الكائن الذي يقوم بإنشاء الكود البني الثابتة الخاصة <T> t getImplobject (الفئة <T> CLS) {try {return (t) class.forname (cls.getName () + "$ inmal"). newinstance () ؛ } catch (استثناء e) {return null ؛ }}قم ببناء وكيل ديناميكي ، ونقله إلى الكائن الحقيقي لـ Realapi ، وكائن التنفيذ للفئة التجريدية التي تم إنشاؤها في الخطوة السابقة ، وتحديد الكائن الذي هو تكييف سلوك الطريقة المستندة إلى التعريف في الفئة التجريدية: إذا كان هناك تعريف في الفئة المجردة ، أي أن الطريقة ليست طريقة تجريدية ، وسيتم تنفيذ كائن التنفيذ في الفئة التجريدية ؛ خلاف ذلك ، سيتم تنفيذه بواسطة الكائن الحقيقي للواجهة.
static public <Origin ، Mock Extring Origin> Origin Build (Origin Origin Final Origin ، Final Class <Mock> mockclass) {// إذا تم وضع علامة على فئة Mock على أنها مغلقة ، فسوف يعيد مباشرة كائن الواجهة الحقيقية إذا (! isenable (mockclass)) {return Orving ؛ } النهائي mockobject = getImPlobject (mockclass) ؛ class <؟> OriginClass = Origin.getClass (). getInterFaces () [0] ؛ return (Orringe) proxy.newproxyinstance (OriginClass.getClassLoader () ، فئة جديدة [] {OriginClass} ، new invocationHandler () {Override Public Object invoke (Object o ، method ، object [] composion) remable {// احصل mockclass.getDeclaredMethod (method.getName () ، method.getParameterTypes ()) ؛ mockmethod.invoke (mockobject ، الكائنات) ؛بعد الانتهاء من العمل أعلاه ، يمكنك استخدام طريقة الإنشاء لإنشاء كائن وكيل يمزج واجهات حقيقية وطرق فئة مجردة كما هو مذكور في البداية. على الرغم من أن فئة الاتصال مرمزة بشكل أساسي ، إلا أنها يتم إنشاؤها تلقائيًا عن طريق معالج التعليقات التوضيحية دون صيانة يدوية. فيما يتعلق بالاستخدام ، فإنه يشبه في الأساس استخدام تنفيذ Javassist.
لقد استخدمت الطريقة التي أنتمي إليها في هذه المقالة لتنفيذ أداة تحاكي طلبات التحديثية (هناك رابط في نهاية المقالة) ، ولكن في جوهرها ، يمكن استخدامها لتنفيذ العديد من الاحتياجات التي تتطلب بناء فصول تجريدية ، وما زالت هناك حاجة إلى المزيد من سيناريوهات الاستخدام.
يمكن العثور على تنفيذ رمز المصدر المذكور في المقالة في المشروع retrofit-mock-result أو التنزيل المحلي ؛
لخص
ما سبق هو المحتوى الكامل لهذه المقالة. آمل أن يكون لمحتوى هذه المقالة قيمة مرجعية معينة لدراسة أو عمل الجميع. إذا كان لديك أي أسئلة ، فيمكنك ترك رسالة للتواصل. شكرا لك على دعمك إلى wulin.com.