1. نظرة عامة <BR /> Agent هو نمط تصميم ، والغرض منه هو تزويد كائن آخر مع وكيل للتحكم في الوصول إلى كائن معين. فئة الوكيل مسؤولة عن رسائل المعالجة المسبقة لفئة المندوبين ، وتصفية الرسائل وإعادة توجيه الرسائل ، وإجراء المعالجة اللاحقة بعد تنفيذ الرسالة بواسطة فئة المندوب. للحفاظ على الاتساق في السلوك ، عادة ما تنفذ فئات الوكيل وفصول تفويض الواجهة نفسها.
وفقًا لفترة إنشاء الوكيل ، يمكن تقسيم فئات الوكيل إلى نوعين:
الوكيل الثابت: يقوم المبرمج بإنشاء فئة وكيل أو أداة محددة لإنشاء التعليمات البرمجية المصدر تلقائيًا ثم تجميعها. وهذا يعني أن ملف .class لفئة الوكيل موجود بالفعل قبل تشغيل البرنامج.
الوكيل الديناميكي: استخدم آلية الانعكاس لإنشاء وإنشاء ديناميكي عند تشغيل البرنامج.
دعنا نقدم باختصار الوكيل الثابت قبل تنفيذ آلية الوكيل الديناميكي.
2. الوكيل الثابت <BR /> كما ذكر أعلاه ، تحتاج كل من فئات الوكيل وفئات المفوض بشكل عام إلى تنفيذ الواجهة نفسها. فيما يلي تحديد هذه الواجهة أولاً:
خدمة الواجهة العامة {public void add () ؛}فئة المندوب هي تنفيذ واجهة ، محددة على النحو التالي:
ServiceImpl Public ServiceImpl تنفذ خدمة {public void add () {system.out.println ("إضافة المستخدم!") ؛ }}إذا أردنا إضافة بعض السجلات إلى فئة المندوب ، يمكن تعريف فئة الوكيل على النحو التالي:
Serviceproxy Serviceproxy Public Service {خدمة الخدمة الخاصة ؛ ServiceProxy (خدمة الخدمة) {super () ؛ this.service = الخدمة ؛ } public void add () {system.out.println ("service start") ؛ service.add () ؛ System.out.println ("Service End") ؛ }}اكتب فصول الاختبار:
الفئة العامة testmain {public static void main (string [] args) {service serviceImpl = new ServiceImpl () ؛ وكيل الخدمة = New ServiceProxy (serviceImpl) ؛ proxy.add () ؛ }}قم بتشغيل برنامج الاختبار ، والنتائج هي كما يلي:
من الكود أعلاه ، يمكننا أن نرى أن فئة الوكيل الثابتة يمكن أن تخدم واجهة محددة فقط. إذا كنت ترغب في تقديم أنواع متعددة من الكائنات ، فيجب عليك وكيل كل كائن. سوف نفكر فيما إذا كان يمكن إكمال جميع وظائف الوكيل من خلال فصل وكيل ، لذلك قدمنا مفهوم الوكيل الديناميكي.
3. الوكيل الديناميكي للوكالة الديناميكية Java يتضمن بشكل أساسي فئتين ، وكيل ودعوة.
الوكيل: يوفر مجموعة من الأساليب الثابتة لإنشاء فئات الوكيل ديناميكيًا وكائناتها لمجموعة من الواجهات.
// الطريقة 1: يتم استخدام هذه الطريقة للحصول على معالج المكالمات المرتبط بكائن الوكيل المحدد. Static InvocationHandler GetInvocationHandler (Proxy Object) // الطريقة 2: يتم استخدام هذه الطريقة للحصول على كائن الفئة لفئة الوكيل الديناميكية المرتبطة بوادر الفئة المحدد ومجموعة من الواجهات. الفئة الثابتة getProxyclass (تحميل classloader ، فئة [] واجهات) // الطريقة 3: يتم استخدام هذه الطريقة لتحديد ما إذا كان كائن الفئة المحدد هو فئة الوكيل الديناميكي الثابتة isproxyclass (clas cl) كائن ثابت NewProxyInstance (Loader ClassLoader ، فئة [] واجهات ، InvocationHandler H)
InvocationHandler: إنها واجهة معالج الاتصال ، وتخصيص طريقة Invok ، والتي يتم استخدامها للتعامل مع مكالمات طريقة المعالجة المركزية على كائنات فئة الوكيل الدينامي
. المعلمة الأولى هي مثيل لفئة الوكيل ، والمعلمة الثانية هي كائن الطريقة التي يتم استدعاؤها // الطريقة الثالثة هي معلمة الاتصال. معالج المكالمات المسبق أو الإرسال إلى مثيل فئة المندوب لنقل كائن التنفيذ استدعاء (وكيل الكائن ، طريقة الطريقة ، الكائن [] args)
لتنفيذ الوكيل الديناميكي لجافا ، هناك أربع خطوات محددة:
1. قم بإنشاء معالج المكالمات الخاص بك عن طريق تطبيق واجهة InvocationHandler
2. قم بإنشاء فئة وكيل ديناميكي عن طريق تحديد كائن classloader ومجموعة من واجهات فئة الوكيل
3. الحصول على مُنشئ فئة الوكيل الديناميكي من خلال آلية الانعكاس ، ونوع المعلمة الوحيد هو نوع واجهة فئة المعالج
4. إنشاء مثيل فئة وكيل ديناميكي من خلال المنشئ. أثناء البناء ، يسمى كائن المعالج كمعلمة ويتم تمريره.
فيما يلي مثال على تنفيذ الوكيل الديناميكي الخاص بك بناءً على الخطوات الأربع المذكورة أعلاه:
فئة تنفيذ الواجهة والواجهة (أي فئة المفوض) هي نفس رمز الوكيل الثابت أعلاه. سنقوم هنا بتنفيذ واجهة InvocationHandler لإنشاء معالج المكالمات الخاص بنا.
ServiceHandle Public ServiceHandle تنفذ invocationHandler {private object s ؛ serviceHandle (Object s) {this.s = s ؛ } الكائن العام استدعاء (وكيل الكائن ، طريقة الطريقة ، الكائن [] args) يلقي رمي {system.out.println ("Service Start") ؛ // Invoke تعني استدعاء الطريقة الأساسية التي يمثلها كائن الطريقة على كائن محدد مع نتيجة كائن المعلمات المحددة = method.invoke (s ، args) ؛ System.out.println ("Service End") ؛ نتيجة العودة }}اكتب فصول الاختبار:
الفئة العامة testmain {public static void main (string [] args) {service service = new ServiceImpl () ؛ معالج InvocationHandler = New ServiceHandle (Service) ؛ Service s = (service) proxy.newproxyinstance (service.getClass (). getClassloader () ، service.getClass (). S.Add () ؛ }}قم بتشغيل برنامج الاختبار ، والنتيجة هي نفس الوكيل الثابت. يمكننا أن نرى أن الكود أعلاه لا يحتوي على خطوتين 2 و 3 ذكرنا من قبل ، لأن طريقة Prox الثابتة NewProxyinstance قد غلفت هاتين الخطوتين بالنسبة لنا. التنفيذ الداخلي المحدد هو كما يلي:
. }))
التنفيذ الداخلي لوظيفة NewProxyInstance هو:
كائن ثابت عام NewProxyInstance (loader classloader ، فئة <؟> [] واجهات ، invocationHandler H) يلقي alfictalargumentexception {// check h ليس فارغًا ، وإلا رمي كائنات استثناء. // احصل على كائن نوع فئة الوكيل المتعلق بصياغة محمل الفئة ومجموعة من واجهات الفئة النهائية <؟> [] intfs = interfaces.clone () ؛ // تحقق مما إذا كان كائن فئة الواجهة مرئيًا لعملية تحميل الفئة وهو بالضبط نفس كائن فئة الواجهة المعترف به من قبل فئة Loader Final SecurityManager SM = System.GetSecurityManager () ؛ if (sm! = null) {checkproxyAccess (Reflection.getCallerClass () ، loader ، intfs) ؛ } // احصل على كائن نوع فئة الوكيل المتعلق بصياغة محمل الفئة ومجموعة من واجهات فئة <؟> cl = getProxyclass0 (loader ، intfs) ؛ جرب {if (sm! = null) {checkNewProxyPermission (Reflection.getCallerClass () ، cl) ؛ } // احصل على كائن المنشئ من خلال الانعكاس وقم بإنشاء منشئ نهائي من فئة الوكيل <؟> cons = cl.getConstructor (constructorms) ؛ InvocationHandler النهائي IH = H ؛ if (! modifier.ispublic (cl.getModifiers ())) {AccessController.doprivileged (new terilegedageAction <Void> () {public void run () {cons.setAccible (true) ؛ return null ؛}}) ؛ } return cons.newinstance (كائن جديد [] {h}) ؛ } catch (alfictAccessException | instantiationException e) {رمي internalerror جديد (e.toString () ، e) ؛ } catch (invocationTargetException e) {throwable t = e.getCause () ؛ if (t extureof runTimeException) {throw (runTimeException) t ؛ } آخر {رمي internalerror جديد (t.toString () ، t) ؛ }} catch (nosuchmethodexception e) {رمي داخلي جديد (e.toString () ، e) ؛ }} 4. محاكاة وتنفيذ فئة الوكيل
وفقًا لمقدمة المبدأ أعلاه ، يمكننا محاكاة وتنفيذ فئة الوكيل بأنفسنا:
Public Class Proxy {public static object newProxyInstance (class inface ، invocationHandle H) يلقي الاستثناء {string rt = "/r/n" ؛ سلسلة methodStr = "" ؛ الطريقة [] الأساليب = inface.getMethods () ؛ لـ (method m: methods) {methodStr+= "@override"+rt+"public void"+m.getName ()+"()"+rt+"{"+rt+"try {"+rt+ "H.invoke (هذا ، MD) ؛"+ rt+ "} catch (استثناء e) {e.printstacktrace () ؛}"+ rt+ "}" ؛ } String src = "package test ؛"+ rt+ "import java.lang.reflect.method ؛"+ rt+ "public class serviceImpl2"+ inface.getName ()+ rt+ "{"+ rt+ "serviceimpl2 (invocationHandle h)"+ rt+ "{rt+" this. test.invocationHandle H ؛ "+ rt+ methodStr+"} "؛ اسم ملف السلسلة = "d: /src/test/serviceimpl2.java" ؛ // compile compile (SRC ، filename) ؛ // تحميل في الذاكرة وإنشاء كائن مثيل M = LoadMemory (H) ؛ العودة م ؛ } ترجمة الفراغ الثابتة الخاصة (سلسلة SRC ، اسم ملف السلسلة) يلقي ioException {file f = new file (filename) ؛ filewriter filewRiter = new filewriter (f) ؛ filewriter.write (SRC) ؛ filewriter.flush () ؛ filewriter.close () ؛ // احصل على برنامج التحويل البرمجي Java المقدم من هذا النظام الأساسي ، Javacompiler Compiler = ToolProvider.getSystemJavAcompiler () ؛ // احصل على مثيل جديد تم تنفيذه بواسطة مدير ملفات قياسي standardjavafileManager fileManager = compiler.getStandardFileManager (null ، null ، null) ؛ // احصل على كائن الملف الذي يمثل الملف المعطى iterable units = fileManager.getJavafileObjects (اسم الملف) ؛ // إنشاء compilationTask في المستقبل t = compiler.getTask (null ، filemanager ، null ، null ، null ، units) ؛ // تنفيذ مهمة التجميع هذه t.call () ؛ filemanager.close () ؛ } محمل الكائن الثابت الخاص (invocationHandle H) يلقي مشوه ، classnotfoundException ، nosuchmethodexception ، instantiationexception ، alfaralalAccessException ، invocationTargetException {url [] url = url new url [] // تحميل فئة وموارد urlclassloader ul = urlClassLoader جديد (urls) ؛ الفئة C = ul.loadClass ("Test.ServiceImpl2") ؛ // إرجاع المُنشئ العام المحدد للفئة التي يمثلها كائن الفئة. مُنشئ ctr = c.getConstructor (invocationHandle.Class) ؛ // استخدم طريقة المنشئ التي يمثلها كائن مُنشئ CTR هذا لإنشاء مثيل جديد لفئة الإعلان لطريقة المنشئ ، وتهيئة المثيل باستخدام كائن معلمة التهيئة المحدد M = ctr.newinstance (H) ؛ العودة م ؛ }}5. ملخص 1. ما يسمى الوكيل الديناميكي هو مثل هذا الفئة. إنه فئة تم إنشاؤها في وقت التشغيل. عند إنشاءه ، يجب عليك توفير مجموعة من الواجهات لها ، ثم تغيير الفصل للادعاء بأنه يطبق هذه الواجهات. ومع ذلك ، فإنه لن يقوم بعمل كبير من أجلك ، ولكنه سيتولى العمل الفعلي بناءً على معالج المعلمات (أي فئة التنفيذ لواجهة InvocationHandler) المقدمة عند إنشاء المثيل.
2. تصميم Proxy يجعله يدعم الواجهة فقط. كانت آلية الميراث في جافا تهدف إلى أن فئة الوكيل الديناميكي لا يمكنها تنفيذ الوكيل الديناميكي للطبقة ، لأن الميراث المتعدد غير ممكن في جافا.
ما سبق هو كل شيء عن هذا المقال ، آمل أن يكون مفيدًا لتعلم الجميع.